/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as box2d from "./box2d/Box2D/Box2D.js";

let runCount = 70000
let runCount_thousnd_1 = 1000
let runCount_thousnad_10 = 10000
let runCount_thousand_100 = 100000
let runCount_Million_5 = 5000000

function b2AABB_Copy_Test() {
  let originalAABB = new box2d.b2AABB();
  originalAABB.lowerBound = new box2d.b2Vec2(0, 0);
  originalAABB.upperBound = new box2d.b2Vec2(10, 10);
  let copiedAABB = new box2d.b2AABB();
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    copiedAABB.Copy(originalAABB);
  }
  const endTime = getDate();
  if (JSON.stringify(copiedAABB) != JSON.stringify(originalAABB)) {
    throw new Error("jBox2d_b2AABB_Copy error");
  }
  print(`jBox2d_b2AABB_Copy: ${endTime - startTime} ms`);
}

function b2AABB_IsValid_Test() {
  let originalAABB = new box2d.b2AABB();
  originalAABB.lowerBound = new box2d.b2Vec2(0, 0);
  originalAABB.upperBound = new box2d.b2Vec2(10, 10);
  let isValid;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    isValid = originalAABB.IsValid();
  }
  const endTime = getDate();
  if (!isValid) {
    throw new Error("jBox2d_b2AABB_IsValid error");
  }
  print(`jBox2d_b2AABB_IsValid: ${endTime - startTime} ms`);
}

function b2AABB_GetCenter_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(0, 0);
  aabb.upperBound = new box2d.b2Vec2(10, 10);
  let center;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    center = aabb.GetCenter();
  }
  const endTime = getDate();
  if (center.x != 5 && center.y != 5) {
    throw new Error("jBox2d_b2AABB_GetCenter error");
  }
  print(`jBox2d_b2AABB_GetCenter: ${endTime - startTime} ms`);
}

function b2AABB_GetExtents_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-1, -1);
  aabb.upperBound = new box2d.b2Vec2(10, 10);
  let extents;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    extents = aabb.GetExtents();
  }
  const endTime = getDate();
  if (extents.x != 5.5 && extents.y != 5.5) {
    throw new Error("jBox2d_b2AABB_GetExtents error");
  }
  print(`jBox2d_b2AABB_GetExtents: ${endTime - startTime} ms`);
}

function b2AABB_GetPerimeter_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(0, 0);
  aabb.upperBound = new box2d.b2Vec2(100, 100);
  let perimeter;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    perimeter = aabb.GetPerimeter();
  }
  const endTime = getDate();
  if (perimeter != 400) {
    throw new Error("jBox2d_b2AABB_GetPerimeter error");
  }
  print(`jBox2d_b2AABB_GetPerimeter: ${endTime - startTime} ms`);
}

function b2AABB_Combine1_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-200, -200);
  aabb.upperBound = new box2d.b2Vec2(500, 500);

  let aabb2 = new box2d.b2AABB();
  aabb2.lowerBound = new box2d.b2Vec2(-500, -100);
  aabb2.upperBound = new box2d.b2Vec2(400, 600);

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    aabb.Combine1(aabb2);
  }
  const endTime = getDate();
  if (
    JSON.stringify(aabb) !=
    '{"lowerBound":{"data":{"0":-500,"1":-200}},"upperBound":{"data":{"0":500,"1":600}},"m_cache_center":{"data":{"0":0,"1":0}},"m_cache_extent":{"data":{"0":0,"1":0}}}'
  ) {
    throw new Error("jBox2d_b2AABB_Combine1 error");
  }
  print(`jBox2d_b2AABB_Combine1: ${endTime - startTime} ms`);
}

function b2AABB_Combine2_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(0, 0);
  aabb.upperBound = new box2d.b2Vec2(500, 500);

  let aabb2 = new box2d.b2AABB();
  aabb2.lowerBound = new box2d.b2Vec2(-500, -500);
  aabb2.upperBound = new box2d.b2Vec2(200, 200);

  let newAABB = new box2d.b2AABB();
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    newAABB.Combine2(aabb, aabb2);
  }
  const endTime = getDate();
  if (
    JSON.stringify(newAABB) !=
    '{"lowerBound":{"data":{"0":-500,"1":-500}},"upperBound":{"data":{"0":500,"1":500}},"m_cache_center":{"data":{"0":0,"1":0}},"m_cache_extent":{"data":{"0":0,"1":0}}}'
  ) {
    throw new Error("jBox2d_b2AABB_Combine2 error");
  }
  print(`jBox2d_b2AABB_Combine2: ${endTime - startTime} ms`);
}

function b2AABB_Combine_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(0, 0);
  aabb.upperBound = new box2d.b2Vec2(500, 500);

  let aabb2 = new box2d.b2AABB();
  aabb2.lowerBound = new box2d.b2Vec2(-500, -500);
  aabb2.upperBound = new box2d.b2Vec2(200, 200);

  let newAABB = new box2d.b2AABB();
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    box2d.b2AABB.Combine(aabb, aabb2, newAABB);
  }
  const endTime = getDate();
  if (
    JSON.stringify(newAABB) !=
    '{"lowerBound":{"data":{"0":-500,"1":-500}},"upperBound":{"data":{"0":500,"1":500}},"m_cache_center":{"data":{"0":0,"1":0}},"m_cache_extent":{"data":{"0":0,"1":0}}}'
  ) {
    throw new Error("jBox2d_b2AABB_Combine error");
  }
  print(`jBox2d_b2AABB_Combine: ${endTime - startTime} ms`);
}

function b2AABB_Contains_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-500, -500);
  aabb.upperBound = new box2d.b2Vec2(500, 500);
  let aabb2 = new box2d.b2AABB();
  aabb2.lowerBound = new box2d.b2Vec2(0, 0);
  aabb2.upperBound = new box2d.b2Vec2(200, 200);

  let isContains;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    isContains = aabb2.Contains(aabb);
  }
  const endTime = getDate();
  if (!isContains) {
    throw new Error("jBox2d_b2AABB_Contains error");
  }
  print(`jBox2d_b2AABB_Contains: ${endTime - startTime} ms`);
}

function b2AABB_RayCast_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(0, 0);
  aabb.upperBound = new box2d.b2Vec2(5, 5);

  let rayInput = new box2d.b2RayCastInput();
  rayInput.p1 = new box2d.b2Vec2(-1, 2);
  rayInput.p2 = new box2d.b2Vec2(3, 1);

  let output = new box2d.b2RayCastOutput();
  let isIntersect;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    isIntersect = aabb.RayCast(output, rayInput);
  }
  const endTime = getDate();
  if (!isIntersect) {
    throw new Error("jBox2d_b2AABB_RayCast error");
  }
  print(`jBox2d_b2AABB_RayCast: ${endTime - startTime} ms`);
}

function b2AABB_TestContain_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-100, -100);
  aabb.upperBound = new box2d.b2Vec2(100, 100);

  let point = new box2d.b2Vec2(50, 0);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    result = aabb.TestContain(point);
  }
  const endTime = getDate();
  if (!result) {
    throw new Error("jBox2d_b2AABB_TestContain error");
  }
  print(`jBox2d_b2AABB_TestContain: ${endTime - startTime} ms`);
}

function b2AABB_TestOverlap_Test() {
  let aabb = new box2d.b2AABB();
  aabb.lowerBound = new box2d.b2Vec2(-100, -100);
  aabb.upperBound = new box2d.b2Vec2(100, 100);

  let aabb1 = new box2d.b2AABB();
  aabb1.lowerBound = new box2d.b2Vec2(50, 50);
  aabb1.upperBound = new box2d.b2Vec2(150, 150);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    result = aabb.TestOverlap(aabb1);
  }
  const endTime = getDate();
  if (!result) {
    throw new Error("jBox2d_b2AABB_TestOverlap error");
  }
  print(`jBox2d_b2AABB_TestOverlap: ${endTime - startTime} ms`);
}

function b2World_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world;
  const startTime = getDate();
  for (let i = 0; i < 100; i++) {
    world = new box2d.b2World(gravity);
  }
  const endTime = getDate();
  if (world.GetGravity().y != -10) {
    throw new Error("jBox2d_b2World error");
  }
  print(`jBox2d_b2World: ${endTime - startTime} ms`);
}

function b2World_CreateBody_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let bd = new box2d.b2BodyDef();
  bd.type = box2d.b2BodyType.b2_dynamicBody;

  let minX = -6.0;
  let maxX = 0.0;
  let minY = 4.0;
  let maxY = 6.0;
  bd.position.Set(
    box2d.b2RandomRange(minX, maxX),
    box2d.b2RandomRange(minY, maxY)
  );
  const startTime = getDate();
  for (let i = 0; i < runCount_thousnad_10; i++) {
    world.CreateBody(bd);
  }
  const endTime = getDate();
  if (world.m_bodyCount == 0) {
    throw new Error("jBox2d_b2World_CreateBody error");
  }
  print(`jBox2d_b2World_CreateBody: ${endTime - startTime} ms`);
}

function b2World_DestroyBody_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let y = new box2d.b2Vec2(-7.0, 0.75);
  let shape = new box2d.b2PolygonShape();
  shape.SetAsBox(0.5, 0.5);
  shape.m_radius = 0;

  let fd = new box2d.b2FixtureDef();
  fd.density = 5.0;
  fd.shape = shape;
  let bd = new box2d.b2BodyDef();
  bd.type = box2d.b2BodyType.b2_dynamicBody;
  bd.position.Set(y.x, y.y);
  for (let i = 0; i < runCount_thousnd_1; i++) {
    let body = world.CreateBody(bd)
    body.CreateFixture(fd)
  }
  const startTime = getDate();
  for (let body = world.m_bodyList; body != null; body = body.m_next) {
    world.DestroyBody(body);
  }
  const endTime = getDate();
  if (world.m_bodyCount != 0) {
    throw new Error("jBox2d_b2World_DestroyBody error");
  }
  print(`jBox2d_b2World_DestroyBody: ${endTime - startTime} ms`);
}

function b2World__Joint_Create_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let bd = new box2d.b2BodyDef();
  bd.position.Set(0.0, 20.0);
  let ground = world.CreateBody(bd);

  let shape = new box2d.b2EdgeShape();
  // 夹具，标记形状
  let sd = new box2d.b2FixtureDef();
  sd.shape = shape;
  sd.density = 0.0;
  sd.restitution = 0.4;

  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(-20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(20.0, -20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(-20.0, 20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(20.0, -20.0));
  ground.CreateFixture(sd);

  let shape1 = new box2d.b2PolygonShape();
  shape1.SetAsBox(0.5, 0.5);
  let fd = new box2d.b2FixtureDef();
  fd.shape = shape1;
  fd.density = 1.0;
  fd.friction = 0.3;

  let passable = true;
  let bd1 = new box2d.b2BodyDef();
  bd1.type = box2d.b2BodyType.b2_dynamicBody;
  bd1.position.Set(0.0, 5.0 /*+ 1.54 * i*/);
  let body = world.CreateBody(bd1);
  body.CreateFixture(fd);

  let gravity1 = 10.0;
  let I = body.GetInertia();
  let mass = body.GetMass();
  let radius = box2d.b2Sqrt((2.0 * I) / mass);

  // b2FrictionJointDef
  let def = new box2d.b2FrictionJointDef();
  def.localAnchorA.SetZero();
  def.localAnchorB.SetZero();
  def.bodyA = ground;
  def.bodyB = body;
  def.collideConnected = true;
  def.maxForce = mass * gravity1;
  def.maxTorque = mass * radius * gravity1;

  let joint;
  const startTime = getDate();
  for (let index = 0; index < runCount_thousnd_1; index++) {
    joint = box2d.b2World._Joint_Create(def);
  }
  const endTime = getDate();
  if (!(joint instanceof box2d.b2FrictionJoint)) {
    passable = false;
  }
  if (!passable) {
    throw new Error("jBox2d_b2World__Joint_Create error");
  }
  print(`jBox2d_b2World__Joint_Create: ${endTime - startTime} ms`);
}

function b2World__Joint_Destroy_Test() {
  const startTime = getDate();
  for (let i = 0; i < 2500000; i++) {
    box2d.b2World._Joint_Destroy();
  }
  const endTime = getDate();
  print(`jBox2d_b2World__Joint_Destroy: ${endTime - startTime} ms`);
}

function b2World_CreateJoint_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let bd = new box2d.b2BodyDef();
  bd.position.Set(0.0, 20.0);
  let ground = world.CreateBody(bd);

  let shape = new box2d.b2EdgeShape();
  // 夹具，标记形状
  let sd = new box2d.b2FixtureDef();
  sd.shape = shape;
  sd.density = 0.0;
  sd.restitution = 0.4;

  // Left
  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(-20.0, 20.0));
  ground.CreateFixture(sd);

  // Right
  shape.Set(new box2d.b2Vec2(20.0, -20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  // Top
  shape.Set(new box2d.b2Vec2(-20.0, 20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  // Bottom
  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(20.0, -20.0));
  ground.CreateFixture(sd);

  let shape1 = new box2d.b2PolygonShape();
  shape1.SetAsBox(0.5, 0.5);
  let fd = new box2d.b2FixtureDef();
  fd.shape = shape1;
  fd.density = 1.0;
  fd.friction = 0.3;

  let bd1 = new box2d.b2BodyDef();
  bd1.type = box2d.b2BodyType.b2_dynamicBody;
  bd1.position.Set(0.0, 5.0);
  let body = world.CreateBody(bd1);
  body.CreateFixture(fd);

  let gravity1 = 10.0;
  let I = body.GetInertia();
  let mass = body.GetMass();
  let radius = box2d.b2Sqrt((2.0 * I) / mass);

  // b2FrictionJointDef
  let def = new box2d.b2FrictionJointDef();
  def.localAnchorA.SetZero();
  def.localAnchorB.SetZero();
  def.bodyA = ground;
  def.bodyB = body;
  def.collideConnected = true;
  def.maxForce = mass * gravity1;
  def.maxTorque = mass * radius * gravity1;
  const startTime = getDate();
  for (let i = 0; i < runCount_thousnd_1; i++) {
    world.CreateJoint(def);
  }
  const endTime = getDate();
  if (world.m_jointCount == 0) {
    throw new Error("jBox2d_b2World_CreateJoint error");
  }
  print(`jBox2d_b2World_CreateJoint: ${endTime - startTime} ms`);
}

function b2World_DestroyJoint_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let bd = new box2d.b2BodyDef();
  bd.position.Set(0.0, 20.0);
  let ground = world.CreateBody(bd);

  let shape = new box2d.b2EdgeShape();
  let sd = new box2d.b2FixtureDef();
  sd.shape = shape;
  sd.density = 0.0;
  sd.restitution = 0.4;

  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(-20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(20.0, -20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(-20.0, 20.0), new box2d.b2Vec2(20.0, 20.0));
  ground.CreateFixture(sd);

  shape.Set(new box2d.b2Vec2(-20.0, -20.0), new box2d.b2Vec2(20.0, -20.0));
  ground.CreateFixture(sd);

  let shape1 = new box2d.b2PolygonShape();
  shape1.SetAsBox(0.5, 0.5);
  let fd = new box2d.b2FixtureDef();
  fd.shape = shape1;
  fd.density = 1.0;
  fd.friction = 0.3;

  for (let i = 0; i < 30000; i++) {
    let bd = new box2d.b2BodyDef();
    bd.type = box2d.b2BodyType.b2_dynamicBody;
    bd.position.Set(0.0, 5.0 + 1.54 * i);
    let body = world.CreateBody(bd);
    body.CreateFixture(fd);

    let gravity = 10.0;
    let I = body.GetInertia();
    let mass = body.GetMass();
    let radius = box2d.b2Sqrt((2.0 * I) / mass);

    // b2FrictionJointDef
    let def = new box2d.b2FrictionJointDef();
    def.localAnchorA.SetZero();
    def.localAnchorB.SetZero();
    def.bodyA = ground;
    def.bodyB = body;
    def.collideConnected = true;
    def.maxForce = mass * gravity;
    def.maxTorque = mass * radius * gravity;

    world.CreateJoint(def);
  }
  const startTime = getDate();
  for (let joint = world.m_jointList; joint != null; joint = joint.m_next) {
    world.DestroyJoint(joint);
  }
  const endTime = getDate();
  if (world.m_jointCount != 0) {
    throw new Error("jBox2d_b2World_DestroyJoint error");
  }
  print(`jBox2d_b2World_DestroyJoint: ${endTime - startTime} ms`);
}

// 粒子系统,可以在物理世界中移动、旋转和碰撞
function b2World_CreateParticleSystem_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2ParticleSystemDef();
  def.density = 2;
  def.gravityScale = 3;
  def.radius = 1.5;
  def.maxCount = 4;
  let passable = true;
  let system;
  const startTime = getDate();
  for (let i = 0; i < runCount_thousnd_1; i++) {
    system = world.CreateParticleSystem(def);
  }
  const endTime = getDate();
  if (
    system.m_inverseDensity != 0.5 ||
    system.m_particleDiameter != 3 ||
    system.m_inverseDiameter != 0.3333333333333333 ||
    system.m_squaredDiameter != 9 ||
    system.m_internalAllocatedCapacity != 4
  ) {
    passable = false;
  }
  if (!passable) {
    throw new Error("jBox2d_b2World_CreateParticleSystem error");
  }
  print(`jBox2d_b2World_CreateParticleSystem: ${endTime - startTime} ms`);
}

function b2World_DestroyParticleSystem_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2ParticleSystemDef();
  let passable = true;
  let system = world.CreateParticleSystem(def);
  const startTime = getDate();
  for (let i = 0; i < runCount_thousand_100; i++) {
    world.DestroyParticleSystem(system);
  }
  const endTime = getDate();
  if (system.m_prev != null || system.m_next != null) {
    passable = false;
  }
  if (!passable) {
    throw new Error("jBox2d_b2World_DestroyParticleSystem error");
  }
  print(`jBox2d_b2World_DestroyParticleSystem: ${endTime - startTime} ms`);
}

function b2World_Step_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let timeStep = 1;
  let velocityIterations = 8;
  let positionIterations = 3;
  let particleIterations = box2d.b2CalculateParticleIterations(
    10,
    0.04,
    1 / 60
  );
  let def = new box2d.b2BodyDef();
  let passable = true;
  let body = world.CreateBody(def);
  body.m_torque = 1;
  body.m_force.Copy(new box2d.b2Vec2(11, 2));
  world.m_bodyList = body;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    world.Step(
      timeStep,
      velocityIterations,
      positionIterations,
      particleIterations
    );
  }
  let endTime = getDate();
  if (
    body.m_torque != 0 &&
    JSON.stringify(body.m_force != '{"data":{"0":0,"1":0}}')
  ) {
    passable = false;
  }
  if (!passable) {
    throw new Error("jBox2d_b2World_Step error");
  }
  print(`jBox2d_b2World_Step: ${endTime - startTime} ms`);
}

function b2World_ClearForces_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();

  let passable = true;
  let body = world.CreateBody(def);
  body.m_force.Set(1, 1);
  body.m_torque = 1;
  world.m_bodyList = body;
  let startTime = getDate();
  for (let i = 0; i < 1000000; i++) {
    world.ClearForces();
  }
  let endTime = getDate();
  if (
    JSON.stringify(body.m_force) != '{"data":{"0":0,"1":0}}' ||
    body.m_torque != 0
  ) {
    passable = false;
  }
  if (!passable) {
    throw new Error("jBox2d_b2World_ClearForces error");
  }
  print(`jBox2d_b2World_ClearForces: ${endTime - startTime} ms`);
}

function b2World_GetBodyList_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let world1 = new box2d.b2World(new box2d.b2Vec2(10, -10));
  let def = new box2d.b2BodyDef();
  world.m_bodyList = new box2d.b2Body(def, world1);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetBodyList();
  }
  let endTime = getDate();
  if (result != world.m_bodyList) {
    throw new Error("jBox2d_b2World_GetBodyList error");
  }
  print(`jBox2d_b2World_GetBodyList: ${endTime - startTime} ms`);
}

function b2World_GetJointList_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  def.position.Set(10.0, -20.0);
  let body = world.CreateBody(def);
  let ground = world.CreateBody(new box2d.b2BodyDef());
  let jointDef = new box2d.b2RevoluteJointDef();
  jointDef.Initialize(ground, body, new box2d.b2Vec2(10.0, -12.0));
  let joint = world.CreateJoint(jointDef);
  world.m_jointList = joint;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetJointList();
  }
  let endTime = getDate();
  if (result != joint) {
    throw new Error("jBox2d_b2World_GetJointList error");
  }
  print(`jBox2d_b2World_GetJointList: ${endTime - startTime} ms`);
}

function b2World_GetParticleSystemList_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2ParticleSystemDef();
  let system = world.CreateParticleSystem(def);
  world.m_particleSystemList = system;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetParticleSystemList();
  }
  let endTime = getDate();
  if (result != system) {
    throw new Error("jBox2d_b2World_GetParticleSystemList error");
  }
  print(`jBox2d_b2World_GetParticleSystemList: ${endTime - startTime} ms`);
}

function b2World_GetContactList_Test() {
    let gravity = new box2d.b2Vec2(0, -10)
    let world = new box2d.b2World(gravity)
    let def = new box2d.b2BodyDef()
    let body = world.CreateBody(def)
    let contact = box2d.b2CircleContact.Create()
    world.m_contactManager.m_contactList = contact

    let result
    const startTime = getDate()
    for (let i = 0; i < runCount_Million_5; i++) {
        result = world.GetContactList()
    }
    let endTime = getDate()
    if (result == null) {
        throw new Error('jBox2d_b2World_GetContactList error')
    }
    print(`jBox2d_b2World_GetContactList: ${endTime - startTime} ms`)
}

function b2World_SetAllowSleeping_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetAllowSleeping(true);
  }
  let endTime = getDate();
  if (world.m_allowSleep != true) {
    throw new Error("jBox2d_b2World_SetAllowSleeping error");
  }
  print(`jBox2d_b2World_SetAllowSleeping: ${endTime - startTime} ms`);
}

function b2World_GetAllowSleeping_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.SetAllowSleeping(true);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetAllowSleeping();
  }
  let endTime = getDate();
  if (result != true) {
    throw new Error("jBox2d_b2World_GetAllowSleeping error");
  }
  print(`jBox2d_b2World_GetAllowSleeping: ${endTime - startTime} ms`);
}

function b2World_SetWarmStarting_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetWarmStarting(false);
  }
  let endTime = getDate();
  if (world.m_warmStarting != false) {
    throw new Error("jBox2d_b2World_SetWarmStarting error");
  }
  print(`jBox2d_b2World_SetWarmStarting: ${endTime - startTime} ms`);
}

function b2World_GetWarmStarting_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.SetWarmStarting(false);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetWarmStarting();
  }
  let endTime = getDate();
  if (result != false) {
    throw new Error("jBox2d_b2World_GetWarmStarting error");
  }
  print(`jBox2d_b2World_GetWarmStarting: ${endTime - startTime} ms`);
}

function b2World_SetContinuousPhysics_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetContinuousPhysics(true);
  }
  let endTime = getDate();
  if (world.m_continuousPhysics != true) {
    throw new Error("jBox2d_b2World_SetContinuousPhysics error");
  }
  print(`jBox2d_b2World_SetContinuousPhysics: ${endTime - startTime} ms`);
}

function b2World_GetContinuousPhysics_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.SetContinuousPhysics(true);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetContinuousPhysics();
  }
  let endTime = getDate();
  if (result != true) {
    throw new Error("jBox2d_b2World_GetContinuousPhysics error");
  }
  print(`jBox2d_b2World_GetContinuousPhysics: ${endTime - startTime} ms`);
}

function b2World_SetSubStepping_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetSubStepping(false);
  }
  let endTime = getDate();
  if (world.m_subStepping != false) {
    throw new Error("jBox2d_b2World_SetSubStepping error");
  }
  print(`jBox2d_b2World_SetSubStepping: ${endTime - startTime} ms`);
}

function b2World_GetSubStepping_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.SetSubStepping(false);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetSubStepping();
  }
  let endTime = getDate();
  if (result != false) {
    throw new Error("jBox2d_b2World_GetSubStepping error");
  }
  print(`jBox2d_b2World_GetSubStepping: ${endTime - startTime} ms`);
}

function b2World_GetProxyCount_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.m_contactManager.m_broadPhase.CreateProxy(new box2d.b2AABB(), this);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetProxyCount();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetProxyCount error");
  }
  print(`jBox2d_b2World_GetProxyCount: ${endTime - startTime} ms`);
}

function b2World_GetBodyCount_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  def.position.Set(
    box2d.b2RandomRange(-6.0, 0.0),
    box2d.b2RandomRange(4.0, 6.0)
  );
  world.CreateBody(def);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetBodyCount();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetBodyCount error");
  }
  print(`jBox2d_b2World_GetBodyCount: ${endTime - startTime} ms`);
}

function b2World_GetJointCount_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let count = runCount;
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  def.position.Set(10.0, -20.0);
  let body = world.CreateBody(def);
  let ground = world.CreateBody(new box2d.b2BodyDef());
  let jointDef = new box2d.b2RevoluteJointDef();
  jointDef.Initialize(ground, body, new box2d.b2Vec2(10.0, -12.0));
  world.CreateJoint(jointDef);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetJointCount();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetJointCount error");
  }
  print(`jBox2d_b2World_GetJointCount: ${endTime - startTime} ms`);
}

// 管理碰撞类数量
function b2World_GetContactCount_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.m_contactManager.m_contactCount = 1;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetContactCount();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetContactCount error");
  }
  print(`jBox2d_b2World_GetContactCount: ${endTime - startTime} ms`);
}

// 平衡动态树，物体碰撞时，将节点进行重新分配
function b2World_GetTreeHeight_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let root = (world.m_contactManager.m_broadPhase.m_tree.m_root =
    new box2d.b2TreeNode());
  root.height = 10;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetTreeHeight();
  }
  let endTime = getDate();
  if (result != 10) {
    throw new Error("jBox2d_b2World_GetTreeHeight error");
  }
  print(`jBox2d_b2World_GetTreeHeight: ${endTime - startTime} ms`);
}

function b2World_GetTreeBalance_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let root = (world.m_contactManager.m_broadPhase.m_tree.m_root =
    new box2d.b2TreeNode());
  root.height = 5;
  root.child1 = new box2d.b2TreeNode();
  root.child1.height = 3;
  root.child2 = new box2d.b2TreeNode();
  root.child2.height = 2;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    result = world.GetTreeBalance();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetTreeBalance error");
  }
  print(`jBox2d_b2World_GetTreeBalance: ${endTime - startTime} ms`);
}

function b2World_GetTreeQuality_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let root = (world.m_contactManager.m_broadPhase.m_tree.m_root =
    new box2d.b2TreeNode());
  root.aabb.lowerBound.Copy(new box2d.b2Vec2(1, 2));
  root.aabb.upperBound.Copy(new box2d.b2Vec2(2, 3));
  root.child1 = new box2d.b2TreeNode();
  root.child2 = new box2d.b2TreeNode();
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    result = world.GetTreeQuality();
  }
  let endTime = getDate();
  if (result != 1) {
    throw new Error("jBox2d_b2World_GetTreeQuality error");
  }
  print(`jBox2d_b2World_GetTreeQuality: ${endTime - startTime} ms`);
}

function b2World_SetGravity_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let gravity1 = new box2d.b2Vec2(0, -9.9);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetGravity(gravity1);
  }
  let endTime = getDate();
  if (world.m_gravity.x != gravity1.x || world.m_gravity.y != gravity1.y) {
    throw new Error("jBox2d_b2World_SetGravity error");
  }
  print(`jBox2d_b2World_SetGravity: ${endTime - startTime} ms`);
}

function b2World_GetGravity_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let gravity1 = new box2d.b2Vec2(0, -9.9);
  world.m_gravity.Copy(gravity1);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetGravity();
  }
  let endTime = getDate();
  if (result.x != gravity1.x || result.y != gravity1.y) {
    throw new Error("jBox2d_b2World_GetGravity error");
  }
  print(`jBox2d_b2World_GetGravity: ${endTime - startTime} ms`);
}

function b2World_IsLocked_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.m_locked = true;
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.IsLocked();
  }
  let endTime = getDate();
  if (result != true) {
    throw new Error("jBox2d_b2World_IsLocked error");
  }
  print(`jBox2d_b2World_IsLocked: ${endTime - startTime} ms`);
}

function b2World_SetAutoClearForces_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetAutoClearForces(true);
  }
  let endTime = getDate();
  if (world.m_clearForces != true) {
    throw new Error("jBox2d_b2World_SetAutoClearForces error");
  }
  print(`jBox2d_b2World_SetAutoClearForces: ${endTime - startTime} ms`);
}

function b2World_GetAutoClearForces_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.SetAutoClearForces(true);
  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = world.GetAutoClearForces();
  }
  let endTime = getDate();
  if (result != true) {
    throw new Error("jBox2d_b2World_GetAutoClearForces error");
  }
  print(`jBox2d_b2World_GetAutoClearForces: ${endTime - startTime} ms`);
}

function b2World_ShiftOrigin_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  def.position.Set(
    box2d.b2RandomRange(-6.0, 0.0),
    box2d.b2RandomRange(4.0, 6.0)
  );
  world.CreateBody(def);
  const oldX = world.m_bodyList.m_xf.p.x;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    world.ShiftOrigin(new box2d.b2Vec2(2, 0));
  }
  let endTime = getDate();
  const newX = world.m_bodyList.m_xf.p.x;
  if (Math.round(oldX - newX) != runCount * 2) {
    throw new Error("jBox2d_b2World_ShiftOrigin error");
  }
  print(`jBox2d_b2World_ShiftOrigin: ${endTime - startTime} ms`);
}

function b2World_GetContactManager_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  world.m_contactManager.m_contactCount = 1;
  world.m_contactManager.m_contactList = box2d.b2EdgeAndCircleContact.Create();
  let manager;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    manager = world.GetContactManager();
  }
  let endTime = getDate();
  if (manager.m_contactCount != 1 || manager.m_contactList == null) {
    throw new Error("jBox2d_b2World_GetContactManager error");
  }
  print(`jBox2d_b2World_GetContactManager: ${endTime - startTime} ms`);
}

function b2World_GetProfile_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let profile;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    profile = world.GetProfile();
  }
  let endTime = getDate();
  if (
    JSON.stringify(profile) !=
    '{"step":0,"collide":0,"solve":0,"solveInit":0,"solveVelocity":0,"solvePosition":0,"broadphase":0,"solveTOI":0}'
  ) {
    throw new Error("jBox2d_b2World_GetProfile error");
  }
  print(`jBox2d_b2World_GetProfile: ${endTime - startTime} ms`);
}

function b2World_AddController_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let controller = new box2d.b2BuoyancyController();
  controller.normal.Set(0.0, 1.0);
  controller.offset = 3.0;
  controller.density = 5.0;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.AddController(controller);
  }
  let endTime = getDate();
  if (world.m_controllerList == null || world.m_controllerCount == 0) {
    throw new Error("jBox2d_b2World_AddController error");
  }
  print(`jBox2d_b2World_AddController: ${endTime - startTime} ms`);
}

function b2World_RemoveController_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let controller = new box2d.b2BuoyancyController();
  controller.normal.Set(0.0, 1.0);
  controller.offset = 3.0;
  controller.density = 5.0;

  for (let i = 0; i < runCount_Million_5; i++) {
    world.AddController(controller);
  }

  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.RemoveController(controller);
  }
  let endTime = getDate();

  if (world.m_controllerList != null || world.m_controllerCount != 0) {
    throw new Error("jBox2d_b2World_RemoveController error");
  }
  print(`jBox2d_b2World_RemoveController: ${endTime - startTime} ms`);
}

function b2Body_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body;
  let startTime = getDate();
  for (let i = 0; i < 10000; i++) {
    body = new box2d.b2Body(def, world);
  }
  let endTime = getDate();
  if (body.GetType() != box2d.b2BodyType.b2_dynamicBody) {
    throw new Error("jBox2d_b2Body error");
  }
  print(`jBox2d_b2Body: ${endTime - startTime} ms`);
}

function b2Body_CreateFixture_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();
  let body = world.CreateBody(def);

  let shape = new box2d.b2PolygonShape();
  shape.Set(
    [
      new box2d.b2Vec2(-4, -2),
    ]
  );
  let startTime = getDate();
  for (let i = 0; i < 5000; i++) {
    body.CreateFixture(shape, 5.0);
  }
  let endTime = getDate();
  if (body.GetFixtureList() == null) {
    throw new Error("jBox2d_b2Body_CreateFixture error");
  }
  print(`jBox2d_b2Body_CreateFixture: ${endTime - startTime} ms`);
}

function b2Body_CreateFixtureDef_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let shape = new box2d.b2PolygonShape();
  shape.Set(
    [
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(4, -2),
      new box2d.b2Vec2(4, 0),
      new box2d.b2Vec2(-4, 0),
    ],
    4
  );
  let def = box2d.b2Body.CreateFixtureShapeDensity_s_def;
  def.shape = shape;
  def.density = 5.0;
  let startTime = getDate();
  for (let i = 0; i < 5000; i++) {
    body.CreateFixtureDef(def);
  }
  let endTime = getDate();
  if (body.m_fixtureCount != 5000) {
    throw new Error("jBox2d_b2Body_CreateFixtureDef error");
  }
  print(`jBox2d_b2Body_CreateFixtureDef: ${endTime - startTime} ms`);
}

function b2Body_CreateFixtureShapeDensity_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  let shape = new box2d.b2CircleShape();
  shape.m_p.SetZero();
  shape.m_radius = 0.1;
  let startTime = getDate();
  for (let i = 0; i < runCount_thousnd_1; i++) {
    body.CreateFixtureShapeDensity(shape, 20);
  }
  let endTime = getDate();
  if (body.m_fixtureList.m_density != 20) {
    throw new Error("jBox2d_b2Body_CreateFixtureShapeDensity error");
  }
  print(`jBox2d_b2Body_CreateFixtureShapeDensity: ${endTime - startTime} ms`);
}

function b2Body_DestroyFixture_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let shape = new box2d.b2PolygonShape();
  shape.Set(
    [
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(4, -2),
      new box2d.b2Vec2(-4, 0),
    ],
    3
  );

  for (let i = 0; i < 5000; i++) {
    body.CreateFixture(shape, 5.0);
  }
  if (body.m_fixtureCount == 0) {
    throw new Error("jBox2d_b2Body_DestroyFixture error");
  }

  let startTime = getDate();
  for (let fixture = body.m_fixtureList; fixture != null; fixture = body.m_fixtureList) {
    body.DestroyFixture(fixture);
  }
  let endTime = getDate();
  if (body.m_fixtureCount != 0) {
    throw new Error("jBox2d_b2Body_DestroyFixture error");
  }
  print(`jBox2d_b2Body_DestroyFixture: ${endTime - startTime} ms`);
}

function b2Body_SetTransformVec_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetTransformVec(new box2d.b2Vec2(0.0, 4.0), 180.0);
  }
  let endTime = getDate();

  if (
    body.m_sweep.c0.x != 0 ||
    body.m_sweep.c0.y != 4 ||
    body.m_sweep.a0 != 180
  ) {
    throw new Error("jBox2d_b2Body_SetTransformVec error");
  }
  print(`jBox2d_b2Body_SetTransformVec: ${endTime - startTime} ms`);
}

function b2Body_SetTransformXY_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetTransformXY(2.0, 5.0, 270.0);
  }
  let endTime = getDate();
  if (
    body.m_sweep.c0.x != 2 ||
    body.m_sweep.c0.y != 5 ||
    body.m_sweep.a0 != 270
  ) {
    throw new Error("jBox2d_b2Body_SetTransformXY error");
  }
  print(`jBox2d_b2Body_SetTransformXY: ${endTime - startTime} ms`);
}

function b2Body_SetTransform_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let xf = new box2d.b2Transform();
  xf.p = new box2d.b2Vec2(5, 10);
  xf.q = new box2d.b2Rot(30);
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetTransform(xf);
  }
  let endTime = getDate();
  if (
    body.m_sweep.c0.x != 5 ||
    body.m_sweep.c0.y != 10 ||
    body.m_sweep.a0 != Math.atan2(Math.sin(30), Math.cos(30))
  ) {
    throw new Error("jBox2d_b2Body_SetTransform error");
  }
  print(`jBox2d_b2Body_SetTransform: ${endTime - startTime} ms`);
}

function b2Body_GetTransform_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.SetTransformXY(2.0, 5.0, 30);
  let xf;
  let startTime = getDate();
  for (let index = 0; index < runCount_Million_5; index++) {
    xf = body.GetTransform();
  }
  let endTime = getDate();
  if (
    xf.p.x != 2 ||
    xf.p.y != 5 ||
    xf.q.s != Math.sin(30) ||
    xf.q.c != Math.cos(30)
  ) {
    throw new Error("jBox2d_b2Body_GetTransform error");
  }
  print(`jBox2d_b2Body_GetTransform: ${endTime - startTime} ms`);
}

function b2Body_GetPosition_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.SetTransformVec(new box2d.b2Vec2(2, 5), 0);

  let p;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    p = body.GetPosition();
  }
  let endTime = getDate();
  if (p.x != 2 || p.y != 5) {
    throw new Error("jBox2d_b2Body_GetPosition error");
  }
  print(`jBox2d_b2Body_GetPosition: ${endTime - startTime} ms`);
}

function b2Body_SetPosition_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  let position = new box2d.b2Vec2(1, 2);
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetPosition(position);
  }
  let endTime = getDate();
  if (body.m_xf.p.x != position.x || body.m_xf.p.y != position.y) {
    throw new Error("jBox2d_b2Body_SetPosition error");
  }
  print(`jBox2d_b2Body_SetPosition: ${endTime - startTime} ms`);
}

function b2Body_SetPositionXY_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  let x = 1;
  let y = 2;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetPositionXY(x, y);
  }
  let endTime = getDate();
  if (body.m_xf.p.x != x || body.m_xf.p.y != y) {
    throw new Error("jBox2d_b2Body_SetPositionXY error");
  }
  print(`jBox2d_b2Body_SetPositionXY: ${endTime - startTime} ms`);
}

function b2Body_GetAngle_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  let angle = 1;
  body.SetAngle(angle);

  let result;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetAngle();
  }
  let endTime = getDate();
  if (result != angle) {
    throw new Error("jBox2d_b2Body_GetAngle error");
  }
  print(`jBox2d_b2Body_GetAngle: ${endTime - startTime} ms`);
}

function b2Body_SetAngle_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  let angle = 1;
  let startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetAngle(angle);
  }
  let endTime = getDate();
  if (body.GetAngle() != angle) {
    throw new Error("jBox2d_b2Body_SetAngle error");
  }
  print(`jBox2d_b2Body_SetAngle: ${endTime - startTime} ms`);
}

function b2Body_GetWorldCenter_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.m_sweep.c.Copy(new box2d.b2Vec2(2, 3));
  let center;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    center = body.GetWorldCenter();
  }
  let endTime = getDate();
  if (JSON.stringify(center) != '{"data":{"0":2,"1":3}}') {
    throw new Error("jBox2d_b2Body_GetWorldCenter error");
  }
  print(`jBox2d_b2Body_GetWorldCenter: ${endTime - startTime} ms`);
}

function b2Body_GetLocalCenter_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.m_sweep.localCenter.Copy(new box2d.b2Vec2(1, 1));

  let startTime = getDate();
  let center;
  for (let i = 0; i < runCount; i++) {
    center = JSON.stringify(body.GetLocalCenter());
  }
  let endTime = getDate();
  if (center != '{"data":{"0":1,"1":1}}') {
    throw new Error("jBox2d_b2Body_GetLocalCenter error");
  }
  print(`jBox2d_b2Body_GetLocalCenter: ${endTime - startTime} ms`);
}

function b2Body_SetLinearVelocity_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.m_type = 1;
  const data = { x: 3, y: 5 };
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetLinearVelocity(data);
  }
  const endTime = getDate();
  if (JSON.stringify(body.m_linearVelocity) != '{"data":{"0":3,"1":5}}') {
    throw new Error("jBox2d_b2Body_SetLinearVelocity error");
  }
  print(`jBox2d_b2Body_SetLinearVelocity: ${endTime - startTime} ms`);
}

function b2Body_GetLinearVelocity_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let data = { x: 2, y: 3 };
  body.SetLinearVelocity(data);
  let vec;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    vec = body.GetLinearVelocity();
  }
  let endTime = getDate();
  if (JSON.stringify(vec) != '{"data":{"0":2,"1":3}}') {
    throw new Error("jBox2d_b2Body_GetLinearVelocity error");
  }
  print(`jBox2d_b2Body_GetLinearVelocity: ${endTime - startTime} ms`);
}

function b2Body_SetAngularVelocity_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let angular = 30;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetAngularVelocity(angular);
  }
  const endTime = getDate();
  if (body.GetAngularVelocity() != angular) {
    throw new Error("jBox2d_b2Body_SetAngularVelocity error");
  }
  print(`jBox2d_b2Body_SetAngularVelocity: ${endTime - startTime} ms`);
}

function b2Body_GetAngularVelocity_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.SetAngularVelocity(10);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetAngularVelocity();
  }
  const endTime = getDate();
  if (result != 0) {
    throw new Error("jBox2d_b2Body_GetAngularVelocity error");
  }
  print(`jBox2d_b2Body_GetAngularVelocity: ${endTime - startTime} ms`);
}

function b2Body_GetDefinition_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let type = box2d.b2BodyType.b2_dynamicBody;
  let angle = 30;
  let vec = new box2d.b2Vec2(2, 3);

  let def = new box2d.b2BodyDef();
  def.type = type;

  let body = world.CreateBody(def);
  body.SetAngle(angle);
  body.SetLinearVelocity(vec);

  let definition;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    definition = body.GetDefinition(def);
  }
  const endTime = getDate();
  if (
    definition.type != type ||
    definition.angle != angle ||
    definition.linearVelocity.x != vec.x ||
    definition.linearVelocity.y != vec.y ||
    definition.userData != null
  ) {
    throw new Error("jBox2d_b2Body_GetDefinition error");
  }
  print(`jBox2d_b2Body_GetDefinition: ${endTime - startTime} ms`);
}

// 给物体施加外力
function b2Body_ApplyForce_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let force = { x: 5, y: 6 };
  let point = { x: -2, y: -3 };
  let loopCount = runCount;

  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    body.ApplyForce(force, point);
  }
  const endTime = getDate();
  if (
    body.m_force.x != loopCount * force.x ||
    body.m_force.y != loopCount * force.y
  ) {
    throw new Error("jBox2d_b2Body_ApplyForce error");
  }
  print(`jBox2d_b2Body_ApplyForce: ${endTime - startTime} ms`);
}

function b2Body_ApplyForceToCenter_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);
  let force = { x: 10, y: 20 };
  let loopCount = runCount;
  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    body.ApplyForceToCenter(force);
  }
  const endTime = getDate();
  if (
    body.m_force.x != loopCount * force.x ||
    body.m_force.y != loopCount * force.y
  ) {
    throw new Error("jBox2d_b2Body_ApplyForceToCenter error");
  }
  print(`jBox2d_b2Body_ApplyForceToCenter: ${endTime - startTime} ms`);
}

// 给物体施加旋转力
function b2Body_ApplyTorque_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);
  let torque = 5;
  let loopCount = runCount_Million_5;

  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    body.ApplyTorque(torque);
  }
  const endTime = getDate();
  if (body.m_torque != loopCount * torque) {
    throw new Error("jBox2d_b2Body_ApplyTorque error");
  }
  print(`jBox2d_b2Body_ApplyTorque: ${endTime - startTime} ms`);
}

// 给物体施加线性冲量
function b2Body_ApplyLinearImpulse_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;

  let ground = world.CreateBody(def);
  ground.m_awakeFlag = true;
  ground.m_angularVelocity = 1;
  ground.m_invMass = 2;
  ground.m_invI = 2;
  ground.m_sweep.c.Copy(new box2d.b2Vec2(2, 3));

  let fd = new box2d.b2FixtureDef();
  fd.shape = new box2d.b2CircleShape(1.2);
  fd.density = 1.0;
  fd.friction = 0.4;
  fd.restitution = 0.3;
  let body = world.CreateBody(def);
  body.CreateFixture(fd);

  const impulse = new box2d.b2Vec2(3, 5);
  const loopCount = runCount;

  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    ground.ApplyLinearImpulse(impulse, body.GetWorldCenter());
  }
  const endTime = getDate();
  if (
    ground.m_linearVelocity.x != loopCount * ground.m_invMass * impulse.x ||
    ground.m_linearVelocity.y != loopCount * ground.m_invMass * impulse.y
  ) {
    throw new Error("jBox2d_b2Body_ApplyLinearImpulse error");
  }
  print(`jBox2d_b2Body_ApplyLinearImpulse: ${endTime - startTime} ms`);
}

function b2Body_ApplyLinearImpulseToCenter_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;

  const vec = new box2d.b2Vec2(1, 1);
  let ground = world.CreateBody(def);
  ground.m_awakeFlag = true;
  ground.m_linearVelocity.Copy(vec);

  let fd = new box2d.b2FixtureDef();
  fd.shape = new box2d.b2CircleShape(1.2);
  fd.density = 5.0;
  fd.friction = 0.3;
  fd.restitution = 0.5;
  let body = world.CreateBody(def);
  body.CreateFixture(fd);

  const impulse = new box2d.b2Vec2(2, 2);
  const loopCount = runCount;

  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    ground.ApplyLinearImpulseToCenter(impulse);
  }
  const endTime = getDate();
  if (
    ground.m_linearVelocity.x !=
      loopCount * ground.m_invMass * impulse.x + vec.x ||
    ground.m_linearVelocity.y !=
      loopCount * ground.m_invMass * impulse.y + vec.y
  ) {
    throw new Error("jBox2d_b2Body_ApplyLinearImpulseToCenter error");
  }
  print(`jBox2d_b2Body_ApplyLinearImpulseToCenter: ${endTime - startTime} ms`);
}

function b2Body_ApplyAngularImpulse_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;

  const inv = 5;
  const impulse = 2;
  const loopCount = runCount_Million_5;
  let ground = world.CreateBody(def);
  ground.m_invI = inv;

  const startTime = getDate();
  for (let i = 0; i < loopCount; i++) {
    ground.ApplyAngularImpulse(impulse);
  }
  const endTime = getDate();
  if (ground.m_angularVelocity != loopCount * ground.m_invI * impulse) {
    throw new Error("jBox2d_b2Body_ApplyAngularImpulse error");
  }
  print(`jBox2d_b2Body_ApplyAngularImpulse: ${endTime - startTime} ms`);
}

function b2Body_GetMass_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let mass;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    mass = body.GetMass();
  }
  const endTime = getDate();
  if (mass != 1) {
    throw new Error("jBox2d_b2Body_GetMass error");
  }
  print(`jBox2d_b2Body_GetMass: ${endTime - startTime} ms`);
}

// 获取刚体转动惯量
function b2Body_GetInertia_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let ground = world.CreateBody(new box2d.b2BodyDef());
  ground.m_I = 5;

  let inertia;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    inertia = ground.GetInertia();
  }
  const endTime = getDate();
  if (inertia != ground.m_I) {
    throw new Error("jBox2d_b2Body_GetInertia error");
  }
  print(`jBox2d_b2Body_GetInertia: ${endTime - startTime} ms`);
}

function b2Body_GetMassData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());
  body.m_mass = 1;
  body.m_I = 2;
  body.m_sweep.localCenter.Copy(new box2d.b2Vec2(2, 3));

  let data = new box2d.b2MassData();

  let massData;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    massData = body.GetMassData(data);
  }
  const endTime = getDate();
  if (
    JSON.stringify(massData) !=
    '{"mass":1,"center":{"data":{"0":2,"1":3}},"I":15}'
  ) {
    throw new Error("jBox2d_b2Body_GetMassData error");
  }
  print(`jBox2d_b2Body_GetMassData: ${endTime - startTime} ms`);
}

function b2Body_SetMassData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let data = new box2d.b2MassData();
  data.mass = 1;
  data.I = 1;
  data.center.Copy(new box2d.b2Vec2(1, 1));

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SetMassData(data);
  }
  const endTime = getDate();
  if (body.m_invMass != 1 || body.m_I != -1 || body.m_invI != -1) {
    throw new Error("jBox2d_b2Body_SetMassData error");
  }
  print(`jBox2d_b2Body_SetMassData: ${endTime - startTime} ms`);
}

function b2Body_ResetMassData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  def.type = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  let data = new box2d.b2MassData();
  data.mass = 5;
  data.I = 10;
  data.center.Copy(new box2d.b2Vec2(1, 1));

  body.SetMassData(data);

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.ResetMassData();
  }
  const endTime = getDate();
  if (
    body.m_mass != 1 ||
    body.m_invMass != 1 ||
    body.m_I != 0 ||
    body.m_invI != 0 ||
    JSON.stringify(body.m_sweep.localCenter) != '{"data":{"0":0,"1":0}}'
  ) {
    throw new Error("jBox2d_b2Body_ResetMassData error");
  }
  print(`jBox2d_b2Body_ResetMassData: ${endTime - startTime} ms`);
}

function b2Body_GetWorldPoint_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let localPoint = { x: 10, y: 20 };
  let out = new box2d.b2Vec2();

  let point;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    point = body.GetWorldPoint(localPoint, out);
  }
  const endTime = getDate();
  if (JSON.stringify(point) != '{"data":{"0":10,"1":20}}') {
    throw new Error("jBox2d_b2Body_GetWorldPoint error");
  }
  print(`jBox2d_b2Body_GetWorldPoint: ${endTime - startTime} ms`);
}

// 获取世界坐标系下向量
function b2Body_GetWorldVector_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let localPoint = { x: 10, y: 20 };
  let out = new box2d.b2Vec2();

  let xf = new box2d.b2Transform();
  xf.q.SetAngle(30);
  body.SetTransform(xf);

  let vector;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    vector = body.GetWorldVector(localPoint, out);
  }
  const endTime = getDate();
  if (
    JSON.stringify(vector) !=
    '{"data":{"0":21.303146362304688,"1":-6.795287132263184}}'
  ) {
    throw new Error("jBox2d_b2Body_GetWorldVector error");
  }
  print(`jBox2d_b2Body_GetWorldVector: ${endTime - startTime} ms`);
}

function b2Body_GetLocalPoint_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let worldPoint = { x: 10, y: 20 };
  let out = new box2d.b2Vec2();
  let xf = new box2d.b2Transform();
  xf.q.SetAngle(60);
  body.SetTransform(xf);

  let point;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    point = body.GetLocalPoint(worldPoint, out);
  }
  const endTime = getDate();
  if (
    JSON.stringify(point) !=
    '{"data":{"0":-15.620342254638672,"1":-16.000152587890625}}'
  ) {
    throw new Error("jBox2d_b2Body_GetLocalPoint error");
  }
  print(`jBox2d_b2Body_GetLocalPoint: ${endTime - startTime} ms`);
}

function b2Body_GetLocalVector_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let worldVector = { x: 1, y: 1 };
  let out = new box2d.b2Vec2(2, 3);
  let xf = new box2d.b2Transform();
  xf.q.SetAngle(90);
  body.SetTransform(xf);
  let vector;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    vector = body.GetLocalVector(worldVector, out);
  }
  const endTime = getDate();
  if (
    JSON.stringify(vector) !=
    '{"data":{"0":0.4459230601787567,"1":-1.34207022190094}}'
  ) {
    throw new Error("jBox2d_b2Body_GetLocalVector error");
  }
  print(`jBox2d_b2Body_GetLocalVector: ${endTime - startTime} ms`);
}

function b2Body_GetLinearVelocityFromWorldPoint_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  const worldPoint = { x: 3, y: 5 };
  let out = new box2d.b2Vec2();

  body.m_linearVelocity.Copy(new box2d.b2Vec2(3, 3));
  body.m_angularVelocity = 3;
  body.m_sweep.c.Copy(new box2d.b2Vec2(1, 2));

  const startTime = getDate();
  let p;
  for (let i = 0; i < runCount; i++) {
    p = body.GetLinearVelocityFromWorldPoint(worldPoint, out);
  }
  const endTime = getDate();
  if (JSON.stringify(p) != '{"data":{"0":-6,"1":9}}') {
    throw new Error("jBox2d_b2Body_GetLinearVelocityFromWorldPoint error");
  }
  print(
    `jBox2d_b2Body_GetLinearVelocityFromWorldPoint: ${endTime - startTime} ms`
  );
}

function b2Body_GetLinearVelocityFromLocalPoint_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let localPoint = { x: -10, y: -20 };
  let out = new box2d.b2Vec2();

  body.m_linearVelocity.Copy(new box2d.b2Vec2(1, 1));
  body.m_angularVelocity = 2;
  body.m_sweep.c.Copy(new box2d.b2Vec2(-2, -3));

  let vector;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    vector = body.GetLinearVelocityFromLocalPoint(localPoint, out);
  }
  const endTime = getDate();
  if (JSON.stringify(vector) != '{"data":{"0":35,"1":-15}}') {
    throw new Error("jBox2d_b2Body_GetLinearVelocityFromLocalPoint error");
  }
  print(
    `jBox2d_b2Body_GetLinearVelocityFromLocalPoint: ${endTime - startTime} ms`
  );
}

function b2Body_GetLinearDamping_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  const damping = 5;

  let def = new box2d.b2BodyDef();
  def.linearDamping = damping;
  let body = world.CreateBody(def);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetLinearDamping();
  }
  const endTime = getDate();
  if (result != damping) {
    throw new Error("jBox2d_b2Body_GetLinearDamping error");
  }
  print(`jBox2d_b2Body_GetLinearDamping: ${endTime - startTime} ms`);
}

function b2Body_SetLinearDamping_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldDamping = 5;
  let def = new box2d.b2BodyDef();
  def.linearDamping = oldDamping;
  let body = world.CreateBody(def);
  if (body.GetLinearDamping() != oldDamping) {
    throw new Error("jBox2d_b2Body_SetLinearDamping error");
  }

  let newDamping = 3;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetLinearDamping(newDamping);
  }
  const endTime = getDate();

  if (body.GetLinearDamping() != newDamping) {
    throw new Error("jBox2d_b2Body_SetLinearDamping error");
  }
  print(`jBox2d_b2Body_SetLinearDamping: ${endTime - startTime} ms`);
}

function b2Body_GetAngularDamping_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let damping = 5;
  let def = new box2d.b2BodyDef();
  def.angularDamping = damping;
  let body = world.CreateBody(def);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetAngularDamping();
  }
  const endTime = getDate();
  if (result != damping) {
    throw new Error("jBox2d_b2Body_GetAngularDamping error");
  }
  print(`jBox2d_b2Body_GetAngularDamping: ${endTime - startTime} ms`);
}

function b2Body_SetAngularDamping_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldAngularDamping = 10;
  let def = new box2d.b2BodyDef();
  def.angularDamping = oldAngularDamping;
  let body = world.CreateBody(def);
  if (body.GetAngularDamping() != oldAngularDamping) {
    throw new Error("jBox2d_b2Body_SetAngularDamping error");
  }

  let newAngularDamping = 20;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetAngularDamping(newAngularDamping);
  }
  const endTime = getDate();
  if (body.GetAngularDamping() != newAngularDamping) {
    throw new Error("jBox2d_b2Body_SetAngularDamping error");
  }
  print(`jBox2d_b2Body_SetAngularDamping: ${endTime - startTime} ms`);
}

function b2Body_GetGravityScale_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let gravityScale = 5;
  let def = new box2d.b2BodyDef();
  def.gravityScale = gravityScale;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetGravityScale();
  }
  const endTime = getDate();
  if (result != gravityScale) {
    throw new Error("jBox2d_b2Body_GetGravityScale error");
  }
  print(`jBox2d_b2Body_GetGravityScale: ${endTime - startTime} ms`);
}

function b2Body_SetGravityScale_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldGravityScale = 5;
  let def = new box2d.b2BodyDef();
  def.gravityScale = oldGravityScale;
  let body = world.CreateBody(def);

  if (body.GetGravityScale() != oldGravityScale) {
    throw new Error("jBox2d_b2Body_SetGravityScale error");
  }

  let newGravityScale = 10;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetGravityScale(newGravityScale);
  }
  const endTime = getDate();
  if (body.GetGravityScale() != newGravityScale) {
    throw new Error("jBox2d_b2Body_SetGravityScale error");
  }
  print(`jBox2d_b2Body_SetGravityScale: ${endTime - startTime} ms`);
}

function b2Body_SetType_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let oldType = box2d.b2BodyType.b2_kinematicBody;
  let def = new box2d.b2BodyDef();
  def.type = oldType;
  let body = world.CreateBody(def);

  if (body.GetType() != oldType) {
    throw new Error("jBox2d_b2Body_SetType error");
  }

  let newType = box2d.b2BodyType.b2_dynamicBody;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetType(newType);
  }
  const endTime = getDate();
  if (body.GetType() != newType) {
    throw new Error("jBox2d_b2Body_SetType error");
  }
  print(`jBox2d_b2Body_SetType: ${endTime - startTime} ms`);
}

function b2Body_GetType_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originType = box2d.b2BodyType.b2_dynamicBody;
  let def = new box2d.b2BodyDef();
  def.type = originType;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetType();
  }
  const endTime = getDate();
  if (result != originType) {
    throw new Error("jBox2d_b2Body_GetType error");
  }
  print(`jBox2d_b2Body_GetType: ${endTime - startTime} ms`);
}

function b2Body_SetBullet_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldBullet = true;
  let def = new box2d.b2BodyDef();
  def.bullet = oldBullet;
  let body = world.CreateBody(def);

  if (body.IsBullet() != oldBullet) {
    throw new Error("jBox2d_b2Body_SetBullet error");
  }

  let newBullet = false;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetBullet(newBullet);
  }
  const endTime = getDate();
  if (body.IsBullet() != newBullet) {
    throw new Error("jBox2d_b2Body_SetBullet error");
  }
  print(`jBox2d_b2Body_SetBullet: ${endTime - startTime} ms`);
}

function b2Body_IsBullet_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originBullet = true;
  let def = new box2d.b2BodyDef();
  def.bullet = originBullet;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.IsBullet();
  }
  const endTime = getDate();
  if (result != originBullet) {
    throw new Error("jBox2d_b2Body_IsBullet error");
  }
  print(`jBox2d_b2Body_IsBullet: ${endTime - startTime} ms`);
}

function b2Body_SetSleepingAllowed_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldAutoSleepFlag = true;
  let def = new box2d.b2BodyDef();
  def.allowSleep = oldAutoSleepFlag;
  let body = world.CreateBody(def);

  if (body.IsSleepingAllowed() != oldAutoSleepFlag) {
    throw new Error("jBox2d_b2Body_SetSleepingAllowed error");
  }

  let newAutoSleepFlag = false;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetSleepingAllowed(newAutoSleepFlag);
  }
  const endTime = getDate();
  if (body.IsSleepingAllowed() != newAutoSleepFlag) {
    throw new Error("jBox2d_b2Body_SetSleepingAllowed error");
  }
  print(`jBox2d_b2Body_SetSleepingAllowed: ${endTime - startTime} ms`);
}

function b2Body_IsSleepingAllowed_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originAutoSleepFlag = true;
  let def = new box2d.b2BodyDef();
  def.allowSleep = originAutoSleepFlag;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.IsSleepingAllowed();
  }
  const endTime = getDate();
  if (result != originAutoSleepFlag) {
    throw new Error("jBox2d_b2Body_IsSleepingAllowed error");
  }
  print(`jBox2d_b2Body_IsSleepingAllowed: ${endTime - startTime} ms`);
}

function b2Body_SetAwake_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let def = new box2d.b2BodyDef();
  def.awake = true;
  def.linearVelocity = new box2d.b2Vec2(1, 2);
  def.angularVelocity = 5;
  let body = world.CreateBody(def);

  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetAwake(false);
  }
  const endTime = getDate();
  if (
    body.m_awakeFlag != false ||
    body.m_linearVelocity.x != 0 ||
    body.m_linearVelocity.y != 0 ||
    body.m_angularVelocity != 0
  ) {
    throw new Error("jBox2d_b2Body_SetAwake error");
  }
  print(`jBox2d_b2Body_SetAwake: ${endTime - startTime} ms`);
}

function b2Body_IsAwake_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originAwake = true;
  let def = new box2d.b2BodyDef();
  def.awake = originAwake;
  let body = world.CreateBody(def);
  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.IsAwake();
  }
  const endTime = getDate();
  if (result != originAwake) {
    throw new Error("jBox2d_b2Body_IsAwake error");
  }
  print(`jBox2d_b2Body_IsAwake: ${endTime - startTime} ms`);
}

function b2Body_SetActive_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldValue = true;
  let def = new box2d.b2BodyDef();
  def.active = oldValue;
  let body = world.CreateBody(def);

  if (body.IsActive() != oldValue) {
    throw new Error("jBox2d_b2Body_SetActive error");
  }

  let newValue = false;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetActive(newValue);
  }
  const endTime = getDate();
  if (body.IsActive() != newValue) {
    throw new Error("jBox2d_b2Body_SetActive error");
  }
  print(`jBox2d_b2Body_SetActive: ${endTime - startTime} ms`);
}

function b2Body_IsActive_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originValue = true;
  let def = new box2d.b2BodyDef();
  def.active = originValue;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.IsActive();
  }
  const endTime = getDate();
  if (result != originValue) {
    throw new Error("jBox2d_b2Body_IsActive error");
  }
  print(`jBox2d_b2Body_IsActive: ${endTime - startTime} ms`);
}

function b2Body_SetFixedRotation_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let def = new box2d.b2BodyDef();
  def.fixedRotation = true;
  def.b2BodyType = box2d.b2BodyType.b2_dynamicBody;
  let body = world.CreateBody(def);

  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetFixedRotation(false);
  }
  const endTime = getDate();
  if (
    body.IsFixedRotation() != false ||
    body.m_mass != 0 ||
    body.m_invMass != 0 ||
    body.m_I != 0 ||
    body.m_invI != 0
  ) {
    throw new Error("jBox2d_b2Body_SetFixedRotation error");
  }
  print(`jBox2d_b2Body_SetFixedRotation: ${endTime - startTime} ms`);
}

function b2Body_IsFixedRotation_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let originValue = true;
  let def = new box2d.b2BodyDef();
  def.fixedRotation = originValue;
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.IsFixedRotation();
  }
  const endTime = getDate();
  if (result != originValue) {
    throw new Error("jBox2d_b2Body_IsFixedRotation error");
  }
  print(`jBox2d_b2Body_IsFixedRotation: ${endTime - startTime} ms`);
}

function b2Body_GetFixtureList_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let def = new box2d.b2BodyDef();
  let body = world.CreateBody(def);

  let shape = new box2d.b2PolygonShape();
  shape.Set(
    [
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(4, -2),
      new box2d.b2Vec2(4, 0),
      new box2d.b2Vec2(-4, 0),
    ],
    4
  );
  body.CreateFixture(shape, 5.0);

  let fixture;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    fixture = body.GetFixtureList();
  }
  const endTime = getDate();
  if (fixture == null || body.m_fixtureCount == 0) {
    throw new Error("jBox2d_b2Body_GetFixtureList error");
  }
  print(`jBox2d_b2Body_GetFixtureList: ${endTime - startTime} ms`);
}

function b2Body_GetJointList_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let def = new box2d.b2MotorJointDef();
  let joint = new box2d.b2MotorJoint(def);
  body.m_jointList = new box2d.b2JointEdge(joint);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetJointList();
  }
  const endTime = getDate();
  if (result == null) {
    throw new Error("jBox2d_b2Body_GetJointList error");
  }
  print(`jBox2d_b2Body_GetJointList: ${endTime - startTime} ms`);
}

function b2Body_GetContactList_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let contact = box2d.b2CircleContact.Create();
  body.m_contactList = contact;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetContactList();
  }
  const endTime = getDate();
  if (result == null) {
    throw new Error("jBox2d_b2Body_GetContactList error");
  }
  print(`jBox2d_b2Body_GetContactList: ${endTime - startTime} ms`);
}

function b2Body_GetNext_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let next = world.CreateBody(new box2d.b2BodyDef());
  body.m_next = next;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetNext();
  }
  const endTime = getDate();
  if (result == null) {
    throw new Error("jBox2d_b2Body_GetNext error");
  }
  print(`jBox2d_b2Body_GetNext: ${endTime - startTime} ms`);
}

function b2Body_GetUserData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let def = new box2d.b2BodyDef();
  def.userData = { x: 1, y: 2 };
  let body = world.CreateBody(def);

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetUserData();
  }
  const endTime = getDate();
  if (result == null) {
    throw new Error("jBox2d_b2Body_GetUserData error");
  }
  print(`jBox2d_b2Body_GetUserData: ${endTime - startTime} ms`);
}

function b2Body_SetUserData_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let oldValue = { x: 1, y: 2 };
  let def = new box2d.b2BodyDef();
  def.userData = oldValue;
  let body = world.CreateBody(def);

  if (
    body.GetUserData().x != oldValue.x ||
    body.GetUserData().y != oldValue.y
  ) {
    throw new Error("jBox2d_b2Body_SetUserData error");
  }

  let newValue = { x: 6, y: 10 };
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    body.SetUserData(newValue);
  }
  const endTime = getDate();
  if (
    body.GetUserData().x != newValue.x ||
    body.GetUserData().y != newValue.y
  ) {
    throw new Error("jBox2d_b2Body_SetUserData error");
  }
  print(`jBox2d_b2Body_SetUserData: ${endTime - startTime} ms`);
}

function b2Body_GetWorld_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let ground = world.CreateBody(new box2d.b2BodyDef());

  let newWorld = new box2d.b2World(new box2d.b2Vec2(0, 1));
  ground.m_world = newWorld;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = ground.GetWorld();
  }
  const endTime = getDate();
  if (
    result == null ||
    JSON.stringify(result.m_gravity) != '{"data":{"0":0,"1":1}}'
  ) {
    throw new Error("jBox2d_b2Body_GetWorld error");
  }
  print(`jBox2d_b2Body_GetWorld: ${endTime - startTime} ms`);
}

function b2Body_SynchronizeFixtures_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let def = new box2d.b2BodyDef();
  def.angle = 1;
  def.position = new box2d.b2Vec2(1, 2);
  let body = world.CreateBody(def);

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SynchronizeFixtures();
  }
  const endTime = getDate();
  if (
    JSON.stringify(box2d.b2Body.SynchronizeFixtures_s_xf1) !=
    '{"p":{"data":{"0":1,"1":2}},"q":{"s":0.8414709848078965,"c":0.5403023058681398}}'
  ) {
    throw new Error("jBox2d_b2Body_SynchronizeFixtures error");
  }
  print(`jBox2d_b2Body_SynchronizeFixtures: ${endTime - startTime} ms`);
}

function b2Body_SynchronizeTransform_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let def = new box2d.b2BodyDef();
  def.angle = 0.8;
  let body = world.CreateBody(def);

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SynchronizeTransform();
  }
  const endTime = getDate();
  if (
    JSON.stringify(body.m_xf.q) !=
    '{"s":0.7173560908995228,"c":0.6967067093471654}'
  ) {
    throw new Error("jBox2d_b2Body_SynchronizeTransform error");
  }
  print(`jBox2d_b2Body_SynchronizeTransform: ${endTime - startTime} ms`);
}

function b2Body_ShouldCollide_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2BodyDef();
  let ground = world.CreateBody(def);
  let body = new box2d.b2Body(def, world);
  body.m_type = box2d.b2BodyType.b2_dynamicBody;
  let shouldCollide = false;
  let startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    shouldCollide = ground.ShouldCollide(body);
  }
  let endTime = getDate();
  if (!shouldCollide) {
    throw new Error("jBox2d_b2Body_ShouldCollide error");
  }
  print(`jBox2d_b2Body_ShouldCollide: ${endTime - startTime} ms`);
}

function b2Body_ShouldCollideConnected_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let bodyDef = new box2d.b2BodyDef();
  let ground = world.CreateBody(bodyDef);
  let other = new box2d.b2Body(bodyDef, world);

  let def = new box2d.b2MotorJointDef();

  let joint = new box2d.b2MotorJoint(def);
  ground.m_jointList = new box2d.b2JointEdge(joint);
  ground.m_jointList.other = other;

  let joint2 = new box2d.b2MotorJoint(def);
  joint2.m_collideConnected = false;
  ground.m_jointList.joint = joint2;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = ground.ShouldCollideConnected(other);
  }
  const endTime = getDate();
  if (result == true) {
    throw new Error("jBox2d_b2Body_ShouldCollideConnected error");
  }
  print(`jBox2d_b2Body_ShouldCollideConnected: ${endTime - startTime} ms`);
}

// 模拟世界时间步进，更新世界状态
function b2Body_Advance_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  let alpha = 4;
  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.Advance(alpha);
  }
  const endTime = getDate();
  if (body.m_sweep.alpha0 != alpha) {
    throw new Error("jBox2d_b2Body_Advance error");
  }
  print(`jBox2d_b2Body_Advance: ${endTime - startTime} ms`);
}

function b2Body_GetControllerList_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));

  let bodyDef = new box2d.b2BodyDef();
  let ground = world.CreateBody(bodyDef);
  let body = new box2d.b2Body(bodyDef, world);

  let controllerEdge = new box2d.b2ContactEdge(new box2d.b2Controller(), body);
  ground.m_controllerList = controllerEdge;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = ground.GetControllerList();
  }
  const endTime = getDate();
  if (result == null) {
    throw new Error("jBox2d_b2Body_GetControllerList error");
  }
  print(`jBox2d_b2Body_GetControllerList: ${endTime - startTime} ms`);
}

function b2Body_GetControllerCount_Test() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10));
  let body = world.CreateBody(new box2d.b2BodyDef());

  const count = 10;
  body.m_controllerCount = count;

  let result;
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = body.GetControllerCount();
  }
  const endTime = getDate();
  if (result != count) {
    throw new Error("jBox2d_b2Body_GetControllerCount error");
  }
  print(`jBox2d_b2Body_GetControllerCount: ${endTime - startTime} ms`);
}

function b2Shape_Test() {
  const radius = 5
  let shape
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape = new box2d.b2Shape(box2d.b2ShapeType.e_circleShape, radius)
  }
  const endTime = getDate()
  if (shape == null || shape.m_type != box2d.b2ShapeType.e_circleShape || shape.m_radius != radius) {
    throw new Error('jBox2d_b2Shape error')
  }
  print(`jBox2d_b2Shape: ${ endTime - startTime } ms`)
}

function b2CircleShape_Clone_Test() {
  let shape = new box2d.b2CircleShape(5)
  let cloneShape
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    cloneShape = shape.Clone()
  }
  const endTime = getDate()
  if (cloneShape === shape) {
    throw new Error('jBox2d_b2CircleShape_Clone error')
  }
  print(`jBox2d_b2CircleShape_Clone: ${ endTime - startTime } ms`)
}

function b2ChainShape_Clone_Test() {
  let shape = new box2d.b2ChainShape()
  let cloneShape
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    cloneShape = shape.Clone()
  }
  const endTime = getDate()
  if (cloneShape === shape) {
    throw new Error('jBox2d_b2ChainShape_Clone error')
  }
  print(`jBox2d_b2ChainShape_Clone: ${ endTime - startTime } ms`)
}

function b2EdgeShape_Clone_Test() {
  let shape = new box2d.b2EdgeShape()
  let cloneShape
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    cloneShape = shape.Clone()
  }
  const endTime = getDate()
  if (cloneShape === shape) {
    throw new Error('jBox2d_b2EdgeShape_Clone error')
  }
  print(`jBox2d_b2EdgeShape_Clone: ${ endTime - startTime } ms`)
}

function b2PolygonShape_Clone_Test() {
  let shape = new box2d.b2PolygonShape()
  let cloneShape
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    cloneShape = shape.Clone()
  }
  const endTime = getDate()
  if (cloneShape === shape) {
    throw new Error('jBox2d_b2PolygonShape_Clone error')
  }
  print(`jBox2d_b2PolygonShape_Clone: ${ endTime - startTime } ms`)
}

function b2CircleShape_Copy_Test() {
  let shape = new box2d.b2CircleShape(5)
  shape.m_p = new box2d.b2Vec2(1, 1)

  let other = new box2d.b2Vec2(0, 1)
  other.m_p = new box2d.b2Vec2(2, 2)
  let obj
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    obj = shape.Copy(other)
  }
  const endTime = getDate()
  if (obj === other) {
    throw new Error('jBox2d_b2CircleShape_Copy error')
  }
  print(`jBox2d_b2CircleShape_Copy: ${ endTime - startTime } ms`)
}

function b2Shape_GetType_Test() {
  let shape = new box2d.b2Shape(box2d.b2ShapeType.e_unknown, 5)
  let type
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    type = shape.GetType()
  }
  const endTime = getDate()
  if (type != box2d.b2ShapeType.e_unknown) {
    throw new Error('jBox2d_b2Shape_GetType error')
  }
  print(`jBox2d_b2Shape_GetType: ${ endTime - startTime } ms`)
}

function b2CircleShape_GetChildCount_Test() {
  let shape = new box2d.b2CircleShape(5)
  let childCount
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    childCount = shape.GetChildCount()
  }
  const endTime = getDate()
  if (childCount != 1) {
    throw new Error('jBox2d_b2CircleShape_GetChildCount error')
  }
  print(`jBox2d_b2CircleShape_GetChildCount: ${ endTime - startTime } ms`)
}

function b2ChainShape_GetChildCount_Test() {
  let shape = new box2d.b2ChainShape()
  let childCount
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    childCount = shape.GetChildCount()
  }
  const endTime = getDate()
  if (childCount != -1) {
    throw new Error('jBox2d_b2ChainShape_GetChildCount error')
  }
  print(`jBox2d_b2ChainShape_GetChildCount: ${ endTime - startTime } ms`)
}

function b2EdgeShape_GetChildCount_Test() {
  let shape = new box2d.b2EdgeShape()
  let childCount
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    childCount = shape.GetChildCount()
  }
  const endTime = getDate()
  if (childCount != 1) {
    throw new Error('jBox2d_b2EdgeShape_GetChildCount error')
  }
  print(`jBox2d_b2EdgeShape_GetChildCount: ${ endTime - startTime } ms`)
}

function b2PolygonShape_GetChildCount_Test() {
  let shape = new box2d.b2PolygonShape()
  let childCount
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    childCount = shape.GetChildCount()
  }
  const endTime = getDate()
  if (childCount != 1) {
    throw new Error('jBox2d_b2PolygonShape_GetChildCount error')
  }
  print(`jBox2d_b2PolygonShape_GetChildCount: ${ endTime - startTime } ms`)
}

function b2CircleShape_TestPoint_Test() {
  let shape = new box2d.b2CircleShape(5)
  shape.Set(new box2d.b2Vec2(1, 2), 10)

  let transform = new box2d.b2Transform()
  transform.SetPositionRotation(new box2d.b2Vec2(2, 3), new box2d.b2Rot(1))

  let vec = new box2d.b2Vec2(1, 5)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.TestPoint(transform, vec)
  }
  const endTime = getDate()
  if (result == false) {
    throw new Error('jBox2d_b2CircleShape_TestPoint error')
  }
  print(`jBox2d_b2CircleShape_TestPoint: ${ endTime - startTime } ms`)
}

function b2ChainShape_TestPoint_Test() {
  let shape = new box2d.b2ChainShape()

  let transform = new box2d.b2Transform()
  transform.SetPositionRotation(new box2d.b2Vec2(2, 3), new box2d.b2Rot(1))

  let vec = new box2d.b2Vec2(1, 5)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    result = shape.TestPoint(transform, vec)
  }
  const endTime = getDate()
  if (result != false) {
    throw new Error('jBox2d_b2ChainShape_TestPoint error')
  }
  print(`jBox2d_b2ChainShape_TestPoint: ${ endTime - startTime } ms`)
}

function b2EdgeShape_TestPoint_Test() {
  let shape = new box2d.b2EdgeShape()

  let transform = new box2d.b2Transform()
  transform.SetPositionRotation(new box2d.b2Vec2(2, 3), new box2d.b2Rot(1))

  let vec = new box2d.b2Vec2(1, 5)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    result = shape.TestPoint(transform, vec)
  }
  const endTime = getDate()
  if (result != false) {
    throw new Error('jBox2d_b2EdgeShape_TestPoint error')
  }
  print(`jBox2d_b2EdgeShape_TestPoint: ${ endTime - startTime } ms`)
}

function b2PolygonShape_TestPoint_Test() {
  let shape = new box2d.b2PolygonShape()

  let transform = new box2d.b2Transform()
  transform.SetPositionRotation(new box2d.b2Vec2(2, 3), new box2d.b2Rot(1))

  let vec = new box2d.b2Vec2(1, 5)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.TestPoint(transform, vec)
  }
  const endTime = getDate()
  if (result != true) {
    throw new Error('jBox2d_b2PolygonShape_TestPoint error')
  }
  print(`jBox2d_b2PolygonShape_TestPoint: ${ endTime - startTime } ms`)
}

function b2CircleShape_ComputeDistance_Test() {
  let shape = new box2d.b2CircleShape()
  let xf = new box2d.b2Transform()
  xf.p.Copy(box2d.b2Rot.MulRV(xf.q, new box2d.b2Vec2(1, 0), new box2d.b2Vec2()))

  let p = new box2d.b2Vec2()
  let normal = new box2d.b2Vec2(1, 2)
  let childIndex = 1
  let distance

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    distance = shape.ComputeDistance(xf, p, normal, childIndex)
  }
  const endTime = getDate()
  if (distance != 1) {
    throw new Error('jBox2d_b2CircleShape_ComputeDistance error')
  }
  print(`jBox2d_b2CircleShape_ComputeDistance: ${ endTime - startTime } ms`)
}

function b2ChainShape_ComputeDistance_Test() {
  let shape = new box2d.b2ChainShape()
  let xf = new box2d.b2Transform()
  xf.p.Copy(box2d.b2Rot.MulRV(xf.q, new box2d.b2Vec2(1, 0), new box2d.b2Vec2()))

  let p = new box2d.b2Vec2()
  let normal = new box2d.b2Vec2(1, 2)
  let childIndex = 1
  let distance

  shape.CreateLoop([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(4, 0),
    new box2d.b2Vec2(-4, 0),
  ], 4)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    distance = shape.ComputeDistance(xf, p, normal, childIndex)
  }
  const endTime = getDate()
  if (distance != 5) {
    throw new Error('jBox2d_b2ChainShape_ComputeDistance error')
  }
  print(`jBox2d_b2ChainShape_ComputeDistance: ${ endTime - startTime } ms`)
}

function b2EdgeShape_ComputeDistance_Test() {
  let shape = new box2d.b2EdgeShape()
  let xf = new box2d.b2Transform()
  xf.p.Copy(box2d.b2Rot.MulRV(xf.q, new box2d.b2Vec2(1, 0), new box2d.b2Vec2()))

  let p = new box2d.b2Vec2()
  let normal = new box2d.b2Vec2(1, 2)
  let childIndex = 1
  let distance

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    distance = shape.ComputeDistance(xf, p, normal, childIndex)
  }
  const endTime = getDate()
  if (distance != 1) {
    throw new Error('jBox2d_b2EdgeShape_ComputeDistance error')
  }
  print(`jBox2d_b2EdgeShape_ComputeDistance: ${ endTime - startTime } ms`)
}

function b2PolygonShape_ComputeDistance_Test() {
  let shape = new box2d.b2PolygonShape()
  let xf = new box2d.b2Transform()
  xf.p.Copy(box2d.b2Rot.MulRV(xf.q, new box2d.b2Vec2(1, 0), new box2d.b2Vec2()))

  let p = new box2d.b2Vec2()
  let normal = new box2d.b2Vec2(1, 2)
  let childIndex = 1
  let distance

  shape.Set([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(4, 0),
    new box2d.b2Vec2(-4, 0),
  ], 4)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    distance = shape.ComputeDistance(xf, p, normal, childIndex)
  }
  const endTime = getDate()
  if (distance != 0) {
    throw new Error('jBox2d_b2PolygonShape_ComputeDistance error')
  }
  print(`jBox2d_b2PolygonShape_ComputeDistance: ${ endTime - startTime } ms`)
}

function b2CircleShape_RayCast_Test() {
  let shape = new box2d.b2CircleShape()

  let output = new box2d.b2RayCastOutput()
  output.fraction = 1
  output.normal = new box2d.b2Vec2(1, 1)

  let input = new box2d.b2RayCastInput()
  input.p1 = new box2d.b2Vec2(1, 2)
  input.p2 = new box2d.b2Vec2(2, 3)
  input.maxFraction = 3

  let xf = new box2d.b2Transform()
  xf.SetPositionRotation(new box2d.b2Vec2(5, 10), new box2d.b2Rot(1))

  let childIndex = 1

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.RayCast(output, input, xf, childIndex)
  }
  const endTime = getDate()
  if (result != false) {
    throw new Error('jBox2d_b2CircleShape_RayCast error')
  }
  print(`jBox2d_b2CircleShape_RayCast: ${ endTime - startTime } ms`)
}

function b2CircleShape_ComputeAABB_Test() {
  let shape = new box2d.b2CircleShape()
  shape.Set(new box2d.b2Vec2(), 2)

  let xf = new box2d.b2Transform()
  xf.SetIdentity()

  let childIndex = 1

  let aabb = new box2d.b2AABB()

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeAABB(aabb, xf, childIndex)
  }
  const endTime = getDate()
  if (JSON.stringify(aabb.lowerBound) != '{"data":{"0":-2,"1":-2}}' 
  || JSON.stringify(aabb.upperBound) != '{"data":{"0":2,"1":2}}') {
    throw new Error('jBox2d_b2CircleShape_ComputeAABB error')
  }
  print(`jBox2d_b2CircleShape_ComputeAABB: ${ endTime - startTime } ms`)
}

function b2CircleShape_ComputeMass_Test() {
  let shape = new box2d.b2CircleShape()
  shape.Set(new box2d.b2Vec2(1, 1), 1)

  let massData = new box2d.b2MassData()
  const density = 1

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeMass(massData, density)
  }
  const endTime = getDate()
  if (JSON.stringify(massData) != '{"mass":3.14159265359,"center":{"data":{"0":1,"1":1}},"I":7.853981633975}') {
    throw new Error('jBox2d_b2CircleShape_ComputeMass error')
  }
  print(`jBox2d_b2CircleShape_ComputeMass: ${ endTime - startTime } ms`)
}

function b2CircleShape_SetupDistanceProxy_Test() {
  let shape = new box2d.b2CircleShape()
  shape.Set(new box2d.b2Vec2(1, 1), 2)

  let input = new box2d.b2DistanceInput()
  let proxy = input.proxyA

  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.SetupDistanceProxy(proxy, 0)
  }
  const endTime = getDate()
  if (JSON.stringify(proxy.m_vertices) != '[{"data":{"0":1,"1":1}},{"data":{"0":0,"1":0}}]') {
    throw new Error('jBox2d_b2CircleShape_SetupDistanceProxy error')
  }
  print(`jBox2d_b2CircleShape_SetupDistanceProxy: ${ endTime - startTime } ms`)
}

function b2CircleShape_ComputeSubmergedArea_Test() {
  let shape = new box2d.b2CircleShape()
  shape.Set(new box2d.b2Vec2(1, 5))

  let offset = 2

  let xf = new box2d.b2Transform()
  xf.SetPositionRotation(new box2d.b2Vec2(1, 1), new box2d.b2Rot(1))

  let c = new box2d.b2Vec2()

  let normal = new box2d.b2Vec2(2, 3)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.ComputeSubmergedArea(normal, offset, xf, c)
  }
  const endTime = getDate()
  if (result != 0) {
    throw new Error('jBox2d_b2CircleShape_ComputeSubmergedArea error')
  }
  print(`jBox2d_b2CircleShape_ComputeSubmergedArea: ${ endTime - startTime } ms`)
}

function b2PolygonShape_Set_Test() {
  let shape = new box2d.b2PolygonShape()
  const startTime = getDate()
  for (let i = 0; i < 5000; i++) {
    shape.Set([
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(4, -2),
      new box2d.b2Vec2(4, 0),
      new box2d.b2Vec2(-4, 0),
    ], 4)
  }
  const endTime = getDate()
  if (JSON.stringify(shape.m_vertices) != '[{"data":{"0":4,"1":-2}},{"data":{"0":4,"1":0}},{"data":{"0":-4,"1":0}},{"data":{"0":-4,"1":-2}}]') {
    throw new Error('jBox2d_b2PolygonShape_Set error')
  }
  print(`jBox2d_b2PolygonShape_Set: ${ endTime - startTime } ms`)
}

function b2PolygonShape_SetAsBox_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(4, 0),
    new box2d.b2Vec2(-4, 0),
  ], 4)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.SetAsBox(2, 4)
  }
  const endTime = getDate()
  if (JSON.stringify(shape.m_vertices) != '[{"data":{"0":-2,"1":-4}},{"data":{"0":2,"1":-4}},{"data":{"0":2,"1":4}},{"data":{"0":-2,"1":4}}]') {
    throw new Error('jBox2d_b2PolygonShape_SetAsBox error')
  }
  print(`jBox2d_b2PolygonShape_SetAsBox: ${ endTime - startTime } ms`)
}

function b2PolygonShape_Validate_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(4, 0),
    new box2d.b2Vec2(-4, 0),
  ], 4)

  let result
  const startTime = getDate()
  for (let i = 0; i < 10000; i++) {
    result = shape.Validate() 
  }
  const endTime = getDate()
  if (result != true) {
    throw new Error('jBox2d_b2PolygonShape_Validate error')
  }
  print(`jBox2d_b2PolygonShape_Validate: ${ endTime - startTime } ms`)
}

function b2ChainShape_Copy_Test() {
  let shape = new box2d.b2ChainShape()

  let other = new box2d.b2ChainShape()
  let obj
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    obj = shape.Copy(other)
  }
  const endTime = getDate()
  if (obj === other) {
    throw new Error('jBox2d_b2ChainShape_Copy error')
  }
  print(`jBox2d_b2ChainShape_Copy: ${ endTime - startTime } ms`)
}

function b2EdgeShape_Copy_Test() {
  let shape = new box2d.b2EdgeShape()

  let other = new box2d.b2EdgeShape()
  let obj
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    obj = shape.Copy(other)
  }
  const endTime = getDate()
  if (obj === other) {
    throw new Error('jBox2d_b2EdgeShape_Copy error')
  }
  print(`jBox2d_b2EdgeShape_Copy: ${ endTime - startTime } ms`)
}

function b2PolygonShape_Copy_Test() {
  let shape = new box2d.b2PolygonShape()

  let other = new box2d.b2PolygonShape()
  let obj
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    obj = shape.Copy(other)
  }
  const endTime = getDate()
  if (obj === other) {
    throw new Error('jBox2d_b2PolygonShape_Copy error')
  }
  print(`jBox2d_b2PolygonShape_Copy: ${ endTime - startTime } ms`)
}

function b2ChainShape_RayCast_Test() {
  let shape = new box2d.b2ChainShape()
  shape.CreateLoop([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(1, 1)
  ], 3)

  let output = new box2d.b2RayCastOutput()

  let input = new box2d.b2RayCastInput()
  input.p1 = new box2d.b2Vec2(1, 2)
  input.p2 = new box2d.b2Vec2(2, 3)
  input.maxFraction = 5

  let xf = new box2d.b2Transform()
  xf.SetIdentity()
  xf.p.Set(23, 5)
  let childIndex = 0

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.RayCast(output, input, xf, childIndex)
  }
  const endTime = getDate()
  if (result != false) {
    throw new Error('jBox2d_b2ChainShape_RayCast error')
  }
  print(`jBox2d_b2ChainShape_RayCast: ${ endTime - startTime } ms`)
} 

function b2EdgeShape_RayCast_Test() {
  let shape = new box2d.b2EdgeShape()
  shape.Set(new box2d.b2Vec2(1, -2), new box2d.b2Vec2(3, 6))

  let output = new box2d.b2RayCastOutput()

  let input = new box2d.b2RayCastInput()
  input.p1 = new box2d.b2Vec2(1, 1)
  input.p2 = new box2d.b2Vec2(2, 2)

  let xf = new box2d.b2Transform()
  let childIndex = 1

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.RayCast(output, input, xf, childIndex)
  }
  const endTime = getDate()
  if (result != true) {
    throw new Error('jBox2d_b2EdgeShape_RayCast error')
  }
  print(`jBox2d_b2EdgeShape_RayCast: ${ endTime - startTime } ms`)
}

function b2PolygonShape_RayCast_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([ 
    new box2d.b2Vec2(1, 1),
    new box2d.b2Vec2(4, 4)
  ], 2)

  let output = new box2d.b2RayCastOutput()

  let input = new box2d.b2RayCastInput()
  input.p1 = new box2d.b2Vec2(0, 2)
  input.p2 = new box2d.b2Vec2(1, 1)

  let xf = new box2d.b2Transform()
  let childIndex = 0

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.RayCast(output, input, xf, childIndex)
  }
  const endTime = getDate()
  if (result != true) {
    throw new Error('jBox2d_b2PolygonShape_RayCast error')
  }
  print(`jBox2d_b2PolygonShape_RayCast: ${ endTime - startTime } ms`)
}

function b2ChainShape_ComputeAABB_Test() {
  let shape = new box2d.b2ChainShape()
  shape.CreateLoop([
    new box2d.b2Vec2(),
    new box2d.b2Vec2(1, 1),
    new box2d.b2Vec2(2, 2)
  ], 3)

  let xf = new box2d.b2Transform()
  xf.SetPositionRotation(new box2d.b2Vec2(1, 1), new box2d.b2Rot(0.3 * box2d.b2_pi))

  let aabb = new box2d.b2AABB()
  let childIndex = 1
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeAABB(aabb, xf, childIndex)
  }
  const endTime = getDate()
  if (JSON.stringify(aabb.lowerBound) != '{"data":{"0":0.5575365424156189,"1":2.3968021869659424}}' 
  || JSON.stringify(aabb.upperBound) != '{"data":{"0":0.7787682414054871,"1":3.793604612350464}}') {
    throw new Error('jBox2d_b2ChainShape_ComputeAABB error')
  }
  print(`jBox2d_b2ChainShape_ComputeAABB: ${ endTime - startTime } ms`)
}

function b2EdgeShape_ComputeAABB_Test() {
  let shape = new box2d.b2EdgeShape()
  shape.Set(new box2d.b2Vec2(), new box2d.b2Vec2(1, 1))

  let xf = new box2d.b2Transform()
  xf.SetIdentity()
  let aabb = new box2d.b2AABB()
  let childIndex = 0
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeAABB(aabb, xf, childIndex)
  }
  const endTime = getDate()
  if (JSON.stringify(aabb.lowerBound) != '{"data":{"0":-0.01600000075995922,"1":-0.01600000075995922}}' 
  || JSON.stringify(aabb.upperBound) != '{"data":{"0":1.0160000324249268,"1":1.0160000324249268}}') {
    throw new Error('jBox2d_b2EdgeShape_ComputeAABB error')
  }
  print(`jBox2d_b2EdgeShape_ComputeAABB: ${ endTime - startTime } ms`)
}

function b2PolygonShape_ComputeAABB_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(),
    new box2d.b2Vec2(1, 1), 
    new box2d.b2Vec2(2, 2)
  ])

  let xf = new box2d.b2Transform()
  xf.SetPosition(new box2d.b2Vec2(1, 1))
  xf.SetRotation(new box2d.b2Rot(30))
  let aabb = new box2d.b2AABB()
  let childIndex = 1
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeAABB(aabb, xf, childIndex)
  }
  const endTime = getDate()
  if (JSON.stringify(aabb.lowerBound) != '{"data":{"0":0.984000027179718,"1":-0.683560311794281}}' 
  || JSON.stringify(aabb.upperBound) != '{"data":{"0":3.3005661964416504,"1":1.0160000324249268}}') {
    throw new Error('jBox2d_b2PolygonShape_ComputeAABB error')
  }
  print(`jBox2d_b2PolygonShape_ComputeAABB: ${ endTime - startTime } ms`)
}

function b2ChainShape_ComputeMass_Test() {
  let shape = new box2d.b2ChainShape()
  let massData = new box2d.b2MassData() 

  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.ComputeMass(massData, 2)
  }
  const endTime = getDate()
  if (JSON.stringify(massData) != '{"mass":0,"center":{"data":{"0":0,"1":0}},"I":0}') {
    throw new Error('jBox2d_b2ChainShape_ComputeMass error')
  }
  print(`jBox2d_b2ChainShape_ComputeMass: ${ endTime - startTime } ms`)
}

function b2EdgeShape_ComputeMass_Test() {
  let shape = new box2d.b2EdgeShape()
  shape.Set(new box2d.b2Vec2(1, 1), new box2d.b2Vec2(2, 2))
  let massData = new box2d.b2MassData()
  massData.center = new box2d.b2Vec2(5, 5)

  const startTime = getDate()
  for (let i = 0; i < 150000; i++) {
    shape.ComputeMass(massData, 1)
  }
  const endTime = getDate()
  if (JSON.stringify(massData) != '{"mass":0,"center":{"data":{"0":1.5,"1":1.5}},"I":0}') {
    throw new Error('jBox2d_b2EdgeShape_ComputeMass error')
  }
  print(`jBox2d_b2EdgeShape_ComputeMass: ${ endTime - startTime } ms`)
}

function b2PolygonShape_ComputeMass_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([new box2d.b2Vec2(1, 1)])
  let massData = new box2d.b2MassData()
  massData.mass = 1
  massData.center = new box2d.b2Vec2(1, 1)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.ComputeMass(massData, 4)
  }
  const endTime = getDate()
  let a = JSON.stringify(massData)
  if (JSON.stringify(massData) != '{"mass":16,"center":{"data":{"0":0,"1":0}},"I":10.666666666666666}') {
    throw new Error('jBox2d_b2PolygonShape_ComputeMass error')
  }
  print(`jBox2d_b2PolygonShape_ComputeMass: ${ endTime - startTime } ms`)
}

function b2ChainShape_SetupDistanceProxy_Test() {
  let shape = new box2d.b2ChainShape()
  shape.CreateLoop([new box2d.b2Vec2(1, 1), new box2d.b2Vec2(2, 2), new box2d.b2Vec2()])
  let input = new box2d.b2DistanceInput()

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.SetupDistanceProxy(input.proxyA, 0)
  }
  const endTime = getDate()
  if (JSON.stringify(input.proxyA.m_vertices) != '[{"data":{"0":1,"1":1}},{"data":{"0":2,"1":2}}]') {
    throw new Error('jBox2d_b2ChainShape_SetupDistanceProxy error')
  }
  print(`jBox2d_b2ChainShape_SetupDistanceProxy: ${ endTime - startTime } ms`)
}

function b2EdgeShape_SetupDistanceProxy_Test() {
  let shape = new box2d.b2EdgeShape()
  shape.Set(new box2d.b2Vec2(2, 4), new box2d.b2Vec2())
  let input = new box2d.b2DistanceInput()

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.SetupDistanceProxy(input.proxyA, 0)
  }
  const endTime = getDate()
  if (JSON.stringify(input.proxyA.m_vertices) != '[{"data":{"0":2,"1":4}},{"data":{"0":0,"1":0}}]') {
    throw new Error('jBox2d_b2EdgeShape_SetupDistanceProxy error')
  }
  print(`jBox2d_b2EdgeShape_SetupDistanceProxy: ${ endTime - startTime } ms`)
}

function b2PolygonShape_SetupDistanceProxy_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(), 
    new box2d.b2Vec2()
  ])
  let proxy = new box2d.b2DistanceProxy()

  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.SetupDistanceProxy(proxy, 0)
  }
  const endTime = getDate()
  if (JSON.stringify(proxy.m_vertices) != '[{"data":{"0":-1,"1":-1}},{"data":{"0":1,"1":-1}},{"data":{"0":1,"1":1}},{"data":{"0":-1,"1":1}}]') {
    throw new Error('jBox2d_b2PolygonShape_SetupDistanceProxy error')
  }
  print(`jBox2d_b2PolygonShape_SetupDistanceProxy: ${ endTime - startTime } ms`)
}

function b2ChainShape_ComputeSubmergedArea_Test() {
  let shape = new box2d.b2ChainShape()

  let offset = 0
  let xf = new box2d.b2Transform()
  let c = new box2d.b2Vec2(2, 2)
  let normal = new box2d.b2Vec2()

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    result = shape.ComputeSubmergedArea(normal, offset, xf, c)
  }
  const endTime = getDate()
  if (result != 0) {
    throw new Error('jBox2d_b2ChainShape_ComputeSubmergedArea error')
  }
  print(`jBox2d_b2ChainShape_ComputeSubmergedArea: ${ endTime - startTime } ms`)
}

function b2EdgeShape_ComputeSubmergedArea_Test() {
  let shape = new box2d.b2EdgeShape()

  let c = new box2d.b2Vec2(0, 2)
  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = shape.ComputeSubmergedArea(new box2d.b2Vec2(), 0, new box2d.b2Transform(), c)
  }
  const endTime = getDate()
  if (result != 0) {
    throw new Error('jBox2d_b2EdgeShape_ComputeSubmergedArea error')
  }
  print(`jBox2d_b2EdgeShape_ComputeSubmergedArea: ${ endTime - startTime } ms`)
}

function b2PolygonShape_ComputeSubmergedArea_Test() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(1, 5),
    new box2d.b2Vec2()
  ])

  let normal = new box2d.b2Vec2()
  let offset = 2

  let xf = new box2d.b2Transform()
  xf.SetPositionRotation(new box2d.b2Vec2(), new box2d.b2Rot(0.2 * box2d.b2_pi))
  let c = new box2d.b2Vec2(1, 1)

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount_thousnd_1; i++) {
     result = shape.ComputeSubmergedArea(normal, offset, xf, c)
  }
  const endTime = getDate()
  if (result != 4) {
    throw new Error('jBox2d_b2PolygonShape_ComputeSubmergedArea error')
  }
  print(`jBox2d_b2PolygonShape_ComputeSubmergedArea: ${ endTime - startTime } ms`)
}

function b2PolygonShape_ComputeCentroid_Test() {
  let vertices = [
    new box2d.b2Vec2(1, 2), 
    new box2d.b2Vec2(1, 1), 
    new box2d.b2Vec2(2, 2), 
    new box2d.b2Vec2(3, 3)
  ]
  let centroid = new box2d.b2Vec2()
  const startTime = getDate()
  for (let i = 0; i < runCount_thousand_100; i++) {
    box2d.b2PolygonShape.ComputeCentroid(vertices, vertices.length, centroid)
  }
  let a = JSON.stringify(centroid)
  const endTime = getDate()
  if (JSON.stringify(centroid) != '{"data":{"0":1.6666666269302368,"1":2}}') {
    throw new Error(`jBox2d_b2PolygonShape_ComputeCentroid error`)
  }
  print(`jBox2d_b2PolygonShape_ComputeCentroid: ${ endTime - startTime } ms`)
}

function b2EdgeShape_Set_Test() {
  let shape = new box2d.b2EdgeShape()
  let params = new box2d.b2Vec2(1, 1)

  if (shape.m_vertex1.x == params.x || shape.m_vertex1.y == params.y) {
    throw new Error('jBox2d_b2EdgeShape_Set error')
  }

  const startTime = getDate()
  for (let i = 0; i < 500000; i++) {
    shape.Set(params, params)
  }
  const endTime = getDate()
  if (shape.m_vertex1.x != params.x || shape.m_vertex1.y != params.y) {
    throw new Error('jBox2d_b2EdgeShape_Set error')
  }
  print(`jBox2d_b2EdgeShape_Set: ${ endTime - startTime } ms`)
}

function b2CircleShape_Set_Test() {
  let shape = new box2d.b2CircleShape()
  let position = new box2d.b2Vec2(1, 1)
  let radius = 5
  if (shape.m_radius != 0) {
    throw new Error('jBox2d_b2CircleShape_Set error')
  }
  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.Set(position, radius)
  }
  const endTime = getDate()
  if (shape.m_radius != radius || shape.m_p.x != position.x || shape.m_p.y != position.y) {
    throw new Error('jBox2d_b2CircleShape_Set error')
  }
  print(`jBox2d_b2CircleShape_Set: ${ endTime - startTime } ms`)
}

function b2ChainShape_CreateLoop_Test_01() {
  let shape = new box2d.b2ChainShape()

  if (shape.m_vertices.length != 0) {
    throw new Error('jBox2d_b2ChainShape_CreateLoop_01 error')
  }
  const startTime = getDate()
  let vertices = [
    new box2d.b2Vec2(1, 1),
    new box2d.b2Vec2(2, 2),
    new box2d.b2Vec2(3, 3)
  ]
  for (let i = 0; i < runCount; i++) {
    shape.CreateLoop(vertices, vertices.length)
  }
  const endTime = getDate()
  if (shape.m_vertices.length != vertices.length + 1) {
    throw new Error('jBox2d_b2ChainShape_CreateLoop(vertices >= 3, loop = 70000) error')
  }
  print(`jBox2d_b2ChainShape_CreateLoop(vertices >= 3, loop = 70000): ${ endTime - startTime } ms`)
}

function b2ChainShape_CreateLoop_Test_02() {
  let shape = new box2d.b2ChainShape()

  if (shape.m_vertices.length != 0) {
    throw new Error('jBox2d_b2ChainShape_CreateLoop_02 error')
  }
  const startTime = getDate()
  let vertices = [
    new box2d.b2Vec2(1, 1),
  ]
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.CreateLoop(vertices, vertices.length)
  }
  const endTime = getDate()
  if (shape.m_vertices.length != 0) {
    throw new Error('jBox2d_b2ChainShape_CreateLoop(vertices < 3, loop = 5000000) error')
  }
  print(`jBox2d_b2ChainShape_CreateLoop(vertices < 3, loop = 5000000): ${ endTime - startTime } ms`)
}

function b2ChainShape_CreateChain_Test() {
  let shape = new box2d.b2ChainShape()
  const vs = box2d.b2Vec2.MakeArray(4)
  vs[0].Set(5.0, 7.0)
  vs[1].Set(6.0, 8.0)
  vs[2].Set(7.0, 8.0)
  vs[3].Set(8.0, 7.0)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.CreateChain(vs, vs.length)
  }
  const endTime = getDate()

  if (shape.m_vertices.length != vs.length) {
    throw new Error('jBox2d_b2ChainShape_CreateChain error')
  }
  print(`jBox2d_b2ChainShape_CreateChain: ${ endTime - startTime } ms`)
}

function b2ChainShape_SetPrevVertex_Test() {
  let shape = new box2d.b2ChainShape()
  const prevVertex = new box2d.b2Vec2(1, 1)
  if (box2d.b2Vec2.IsEqualToV(shape.m_prevVertex, prevVertex) ) {
    throw new Error('jBox2d_b2ChainShape_SetPrevVertex error')
  }

  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.SetPrevVertex(prevVertex)
  }
  const endTime = getDate()

  if (!box2d.b2Vec2.IsEqualToV(shape.m_prevVertex, prevVertex)) {
    throw new Error('jBox2d_b2ChainShape_SetPrevVertex error')
  }
  print(`jBox2d_b2ChainShape_SetPrevVertex: ${ endTime - startTime } ms`)
}

function b2ChainShape_SetNextVertex_Test() {
  let shape = new box2d.b2ChainShape()
  const nextVertex = new box2d.b2Vec2(2, 2)
  if (box2d.b2Vec2.IsEqualToV(shape.m_nextVertex, nextVertex) ) {
    throw new Error('jBox2d_b2ChainShape_SetNextVertex error')
  }

  const startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shape.SetNextVertex(nextVertex)
  }
  const endTime = getDate()

  if (!box2d.b2Vec2.IsEqualToV(shape.m_nextVertex, nextVertex)) {
    throw new Error('jBox2d_b2ChainShape_SetNextVertex error')
  }
  print(`jBox2d_b2ChainShape_SetNextVertex: ${ endTime - startTime } ms`)
}

function b2ChainShape_GetChildEdge_Test() {
  const radius = 3

  let shape = new box2d.b2ChainShape()
  shape.m_radius = radius
  shape.CreateLoop([
    new box2d.b2Vec2(1, 1),
    new box2d.b2Vec2(2, 1),
    new box2d.b2Vec2(3, 1),
    new box2d.b2Vec2(2, 2)
  ])
  
  const index = 1
  

  let edge = new box2d.b2EdgeShape()
  edge.m_radius = 5

  const vertex1 = new box2d.b2Vec2().Copy(edge.m_vertex1)
  const vertex2 = new box2d.b2Vec2().Copy(edge.m_vertex2)

  const startTime = getDate()
  for (let i = 0; i < runCount_thousand_100; i++) {
    shape.GetChildEdge(edge, index)
  }

  const endTime = getDate()
  if (edge.m_radius != radius 
    || box2d.b2Vec2.IsEqualToV(edge.m_vertex1, vertex1) 
    || box2d.b2Vec2.IsEqualToV(edge.m_vertex2, vertex2)) {
    throw new Error('jBox2d_b2ChainShape_GetChildEdge error')
  }
  print(`jBox2d_b2ChainShape_GetChildEdge: ${ endTime - startTime } ms`)
}

// 计算粒子迭代次数
function b2World_CalculateReasonableParticleIterations_Test() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2ParticleSystemDef();
  let system = world.CreateParticleSystem(def);
  system.SetRadius(5)
  world.m_particleSystemList = system;

  const timeStep = 1

  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = world.CalculateReasonableParticleIterations(timeStep)
  }
  const endTime = getDate()
  if (result != 8) {
    throw new Error('jBox2d_b2World_CalculateReasonableParticleIterations error')
  }
  print(`jBox2d_b2World_CalculateReasonableParticleIterations: ${ endTime - startTime } ms`)
}

function b2Fixture_ComputeDistance_Test() {
  const bd = new box2d.b2BodyDef();
  const gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let body= world.CreateBody(bd);

  let def = new box2d.b2FixtureDef();
  let shape = new box2d.b2CircleShape(2);
  def.shape = shape;
  def.density = 0;
  let fixture = new box2d.b2Fixture(body, def);
  let p = new box2d.b2Vec2(-2, 3);
  let normal = new box2d.b2Vec2(5, 2);
  let childIndex = 0
  let result
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    result = fixture.ComputeDistance(p, normal, childIndex)
  }
  const endTime = getDate()
  if (result != 1.6055512754639891) {
    throw new Error('jBox2d_b2Fixture_ComputeDistance error')
  }
  print(`jBox2d_b2Fixture_ComputeDistance: ${ endTime - startTime } ms`)
}

// 碰撞检测
function b2Fixture_RayCast_Test() {
  let bd = new box2d.b2BodyDef();
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let body= world.CreateBody(bd);

  let def = new box2d.b2FixtureDef();
  let shape = new box2d.b2CircleShape(2);
  def.shape = shape;
  def.density = 0;
  let fixture = new box2d.b2Fixture(body, def);
  let output = new box2d.b2RayCastOutput();
  let input = new box2d.b2RayCastInput();
  let childIndex = 0;

  let flag
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    flag = fixture.RayCast(output, input, childIndex)
  }
  const endTime = getDate()
  if (flag != false) {
    throw new Error('jBox2d_b2Fixture_RayCast error')
  }
  print(`jBox2d_b2Fixture_RayCast: ${ endTime - startTime } ms`)
}

function b2Fixture_GetMassData_Test() {
  let bodyDef = new box2d.b2BodyDef()
  const gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)
  let body = world.CreateBody(bodyDef)

  let shape = new box2d.b2CircleShape(2)
  let def = new box2d.b2FixtureDef()
  def.shape = shape
  def.density = 0
  let fixture = new box2d.b2Fixture(body, def)
  fixture.m_density = 1
  let massData 
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    massData = fixture.GetMassData()
  }
  const endTime = getDate()
  if (JSON.stringify(massData) != '{"mass":12.56637061436,"center":{"data":{"0":0,"1":0}},"I":25.13274122872}') {
    throw new Error('jBox2d_b2Fixture_GetMassData error')
  }
  print(`jBox2d_b2Fixture_GetMassData: ${ endTime - startTime } ms`)
}

function b2Fixture_GetAABB_Test() {
  let bodyDef = new box2d.b2BodyDef();
  const gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let body = world.CreateBody(bodyDef);

  let def = new box2d.b2FixtureDef();
  let shape = new box2d.b2CircleShape(2);
  def.shape = shape;
  def.density = 0;
  let fixture = new box2d.b2Fixture(body, def);
  let proxy = new box2d.b2FixtureProxy(fixture, 0);
  proxy.aabb.lowerBound.Copy(new box2d.b2Vec2(5, 7));
  proxy.aabb.upperBound.Copy(new box2d.b2Vec2(2, 8));
  fixture.m_proxies.push(proxy)

  const startTime = getDate()
  
  let result
  for (let i = 0; i < runCount_Million_5; i++) {
    result = fixture.GetAABB(0)
  }
  const endTime = getDate()
  if (JSON.stringify(result.lowerBound) != '{"data":{"0":5,"1":7}}' || JSON.stringify(result.upperBound) != '{"data":{"0":2,"1":8}}') {
    throw new Error('jBox2d_b2Fixture_GetAABB error')
  }
  print(`jBox2d_b2Fixture_GetAABB: ${ endTime - startTime } ms`)
}

function b2Fixture_TestPoint_Test() {
  let bodyDef = new box2d.b2BodyDef();
  const gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let body = world.CreateBody(bodyDef);

  let def = new box2d.b2FixtureDef();
  let shape = new box2d.b2CircleShape(2);
  def.shape = shape;
  def.density = 0;
  let fixture = new box2d.b2Fixture(body, def);
  let p = { x: -1, y: -2 }
  let flag
  const startTime = getDate()
  for (let i = 0; i < 500000; i++) {
    flag = fixture.TestPoint(p)
  }
  const endTime = getDate()
  if (flag != false) {
    throw new Error('jBox2d_b2Fixture_TestPoint error')
  }
  print(`jBox2d_b2Fixture_TestPoint: ${ endTime - startTime } ms`)
}

function b2World_GetTreeBalance_Test_01() {
    let gravity = new box2d.b2Vec2(0, -10)
    let world = new box2d.b2World(gravity)

    let treeBalance
    const startTime = getDate()
    for (let i = 0; i < runCount_Million_5; i++) {
      treeBalance = world.GetTreeBalance()
    }
    const endTime = getDate()
    if (treeBalance != 0) {
      throw new Error('jBox2d_b2World_GetTreeBalance(world.m_contactManager.m_broadPhase.m_tree.m_root = null) error')
    }
    print(`jBox2d_b2World_GetTreeBalance(world.m_contactManager.m_broadPhase.m_tree.m_root = null): ${ endTime - startTime } ms`)
}

function b2World_CreateParticleSystem_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)
  let def = new box2d.b2ParticleSystemDef()
  
  let system
  const startTime = getDate()
  for (let i = 0; i < runCount_thousnd_1; i++) {
    system = world.CreateParticleSystem(def)
  }

  const endTime = getDate()
  if (system.m_inverseDensity != 1 
    || system.m_particleDiameter != 2 
    || system.m_inverseDiameter != 0.5 
    || system.m_squaredDiameter != 4 
    || system.m_internalAllocatedCapacity != 256) {
    throw new Error('jBox2d_b2World_CreateParticleSystem(def property default) error')
  }
  print(`jBox2d_b2World_CreateParticleSystem_01(def property default): ${ endTime - startTime } ms`)
}

// 销毁粒子系统
function b2World_DestroyParticleSystem_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2ParticleSystemDef();
  let system = world.CreateParticleSystem(def);

  world.m_particleSystemList = system;

  let preDef = new box2d.b2ParticleSystemDef()
  let prev = world.CreateParticleSystem(preDef)
  system.m_prev = prev
    
  let nextDef = new box2d.b2ParticleSystemDef()
  let next = world.CreateParticleSystem(nextDef)
  system.m_next = next

  const startTime = getDate()
  for (let i = 0; i < runCount_thousand_100; i++) {
    world.DestroyParticleSystem(system)
  }
  const endTime = getDate()
  if (world.m_particleSystemList !== next 
    || system.m_prev.m_next != next 
    || system.m_next.m_prev != prev) {
    throw new Error('jBox2d_b2World_DestroyParticleSystem(world.m_particleSystemList != null,system.m_prev != null, system.m_next != null) error')
  }
  print(`jBox2d_b2World_DestroyParticleSystem(world.m_particleSystemList != null,system.m_prev != null, system.m_next != null): ${ endTime - startTime } ms`)
}

function b2World_ShiftOrigin_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)

  let ground = world.CreateBody(new box2d.b2BodyDef())

  let def = new box2d.b2BodyDef()
  def.type = box2d.b2BodyType.b2_dynamicBody
  def.position.Set(
    box2d.b2RandomRange(-6.0, 0.0),
    box2d.b2RandomRange(4.0, 6.0)
  )
  let body = new box2d.b2Body(def, world)

  let jointDef = new box2d.b2RevoluteJointDef()
  jointDef.Initialize(ground, body, new box2d.b2Vec2(10.0, 12.0))
  world.CreateJoint(jointDef)

  const oldX = world.m_bodyList.m_xf.p.x
  let startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    world.ShiftOrigin(new box2d.b2Vec2(2, 0))
  }
  let endTime = getDate()
  const newX = world.m_bodyList.m_xf.p.x
  if (Math.round(oldX - newX) != runCount * 2) {
    throw new Error("jBox2d_b2World_ShiftOrigin(world.m_jointList != null) error")
  }
  print(`jBox2d_b2World_ShiftOrigin(world.m_jointList != null): ${endTime - startTime} ms`)
}

function b2World_SetAllowSleeping_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)

  let def = new box2d.b2BodyDef()
  let body = world.CreateBody(def)
  body.m_torque = 1
  body.m_force.Copy(new box2d.b2Vec2(11, 2))
  world.m_bodyList = body

  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    world.SetAllowSleeping(false);
  }
  const endTime = getDate();
  if (world.m_allowSleep != false) {
    throw new Error("jBox2d_b2World_SetAllowSleeping(world.m_bodyList != null) error");
  }
  print(`jBox2d_b2World_SetAllowSleeping(world.m_bodyList != null): ${endTime - startTime} ms`);
}

function b2World_GetProfile_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);

  let ground = world.CreateBody(new box2d.b2BodyDef())
  let shape1 = new box2d.b2PolygonShape()
  shape1.SetAsBox(0, 0)
  shape1.radius = 0
  let fd = new box2d.b2FixtureDef()
  fd.density = 0
  fd.shape = shape1
  ground.CreateFixture(fd)

  let def = new box2d.b2BodyDef()
  def.type = box2d.b2BodyType.b2_dynamicBody
  let body = world.CreateBody(def)
  let shape2 = new box2d.b2PolygonShape()
  shape2.Set([new box2d.b2Vec2(-4, -2)])
  body.CreateFixture(shape2, 5.0)

  world.Step(1 / 60, 10, 3)

  let profile
  let startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    profile = world.GetProfile()
  }
  let endTime = getDate()
  if (
    JSON.stringify(profile) ==
    '{"step":0,"collide":0,"solve":0,"solveInit":0,"solveVelocity":0,"solvePosition":0,"broadphase":0,"solveTOI":0}'
  ) {
    throw new Error("jBox2d_b2World_GetProfile(use step setting) error")
  }
  print(`jBox2d_b2World_GetProfile(use step setting): ${endTime - startTime} ms`)
}

function b2World_DestroyBody_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let y = new box2d.b2Vec2(-7.0, 0.75);
  let shape = new box2d.b2PolygonShape();
  shape.SetAsBox(0.5, 0.5);
  shape.m_radius = 5;

  for (let i = 0; i < runCount_thousnad_10; i++) {
    let fd = new box2d.b2FixtureDef()
    fd.density = 5.0
    fd.shape = shape
    let bd = new box2d.b2BodyDef()
    bd.type = box2d.b2BodyType.b2_dynamicBody
    bd.position.Set(y.x, y.y)
    let body = world.CreateBody(bd)
    body.CreateFixture(fd)

    // joint
    let jointdDef = new box2d.b2MotorJointDef()
    let joint = new box2d.b2MotorJoint(jointdDef)
    joint.m_bodyA = new box2d.b2Body(world, new box2d.b2BodyDef())
    joint.m_bodyB = new box2d.b2Body(world, new box2d.b2BodyDef())
    body.m_jointList = new box2d.b2JointEdge(joint)
  }

  const startTime = getDate();
  for (let body = world.m_bodyList; body != null; body = body.m_next) {
    world.DestroyBody(body);
  }
  const endTime = getDate();
  if (world.m_bodyCount != 0) {
    throw new Error("jBox2d_b2World_DestroyBody(world.m_bodyList.m_jointList != null) error");
  }
  print(`jBox2d_b2World_DestroyBody(world.m_bodyList.m_jointList != null): ${endTime - startTime} ms`);
}

function b2Body_CreateFixture_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10);
  let world = new box2d.b2World(gravity);
  let def = new box2d.b2BodyDef();
  let body = world.CreateBody(def);
  body.m_activeFlag = true

  let shape = new box2d.b2ChainShape();
  shape.CreateLoop(
    [
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(-2, -2),
      new box2d.b2Vec2(-3, -1),
      new box2d.b2Vec2(-3, -3)
    ]
  );
  let startTime = getDate();
  for (let i = 0; i < runCount_thousnd_1; i++) {
    body.CreateFixture(shape, 0.0);
  }
  let endTime = getDate();
  if (body.GetFixtureList() == null) {
    throw new Error("jBox2d_b2Body_CreateFixture(shape.m_vertices > 3, CreateFixture.density = 0.0, body.m_activeFlag = true) error");
  }
  print(`jBox2d_b2Body_CreateFixture(shape.m_vertices > 3, CreateFixture.density = 0.0, body.m_activeFlag = true): ${endTime - startTime} ms`);
}

function b2Body_DestroyFixture_Test_01() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10))

  let body = world.CreateBody(new box2d.b2BodyDef())
  let contact = box2d.b2PolygonContact.Create()
  body.m_contactList = new box2d.b2ContactEdge(contact)
  body.m_activeFlag = true

  let shape = new box2d.b2PolygonShape()
  shape.Set([new box2d.b2Vec2(-4, -2)])

  for (let i = 0; i < 20000; i++) {
    body.CreateFixture(shape, 0.0)
  }
  if (body.m_fixtureCount == 0) {
    throw new Error("jBox2d_b2Body_DestroyFixture_01 error")
  }

  let startTime = getDate();
  for (let fixture = body.m_fixtureList; fixture != null; fixture = body.m_fixtureList) {
    body.DestroyFixture(fixture)
  }
  let endTime = getDate()
  if (body.m_fixtureCount != 0) {
    throw new Error("jBox2d_b2Body_DestroyFixture(body.m_contactList != null, body.m_activeFlag = true, shape.m_vertices < 3) error")
  }
  print(`jBox2d_b2Body_DestroyFixture(body.m_contactList != null, body.m_activeFlag = true, shape.m_vertices < 3): ${endTime - startTime} ms`)
}

function b2Body_SetTransform_Test_01() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10))

  let body = world.CreateBody(new box2d.b2BodyDef())
  body.m_activeFlag = true
  let shape = new box2d.b2PolygonShape()
  shape.Set([new box2d.b2Vec2(-4, -2)])
  body.CreateFixture(shape, 0.0)

  let xf = new box2d.b2Transform()
  xf.SetPositionRotation(new box2d.b2Vec2(5, 10), new box2d.b2Rot(30))
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    body.SetTransform(xf)
  }
  const endTime = getDate()

  if (
    body.m_sweep.c0.x != 5 ||
    body.m_sweep.c0.y != 10 ||
    body.m_sweep.a0 != Math.atan2(Math.sin(30), Math.cos(30))
  ) {
    throw new Error("jBox2d_b2Body_SetTransform(body.m_activeFlag = true, body.m_fixtureList != null) error");
  }
  print(`jBox2d_b2Body_SetTransform(body.m_activeFlag = true, body.m_fixtureList != null): ${endTime - startTime} ms`)
}

function b2Body_SetTransformXY_Test_01() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10))
  let body = world.CreateBody(new box2d.b2BodyDef())
  body.m_activeFlag = true
  let shape = new box2d.b2ChainShape()
  shape.CreateLoop([
    new box2d.b2Vec2(1, 1),
    new box2d.b2Vec2(2, 2),
    new box2d.b2Vec2(3, 3)])
  body.CreateFixture(shape, 0.0)

  let startTime = getDate()
  for (let i = 0; i < runCount_thousnd_1; i++) {
    body.SetTransformXY(2.0, 5.0, 270.0)
  }
  let endTime = getDate();
  if (
    body.m_sweep.c0.x != 2 ||
    body.m_sweep.c0.y != 5 ||
    body.m_sweep.a0 != 270
  ) {
    throw new Error("jBox2d_b2Body_SetTransformXY(body.m_activeFlag = true, body.m_fixtureList != null) error");
  }
  print(`jBox2d_b2Body_SetTransformXY(body.m_activeFlag = true, body.m_fixtureList != null): ${endTime - startTime} ms`)
}

function b2Body_ShouldCollide_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)

  let def = new box2d.b2BodyDef()
  def.type = box2d.b2BodyType.b2_dynamicBody
  let ground = world.CreateBody(def)

  let body = new box2d.b2Body(def, world)

  let jointdDef = new box2d.b2MotorJointDef()
  let joint = new box2d.b2MotorJoint(jointdDef)
  body.m_jointList = new box2d.b2JointEdge(joint)

  let shouldCollide = false
  let startTime = getDate()
  for (let i = 0; i < runCount_Million_5; i++) {
    shouldCollide = ground.ShouldCollide(body)
  }
  let endTime = getDate()
  if (!shouldCollide) {
    throw new Error("jBox2d_b2Body_ShouldCollide(body.m_jointList != null) error")
  }
  print(`jBox2d_b2Body_ShouldCollide(body.m_jointList != null): ${endTime - startTime} ms`)
}

function b2Body_ShouldCollideConnected_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity)

  let bodyDef = new box2d.b2BodyDef()
  let ground = world.CreateBody(bodyDef)
  let other = new box2d.b2Body(bodyDef, world)

  let result
  const startTime = getDate();
  for (let i = 0; i < runCount_Million_5; i++) {
    result = ground.ShouldCollideConnected(other)
  }
  const endTime = getDate();
  if (result != true) {
    throw new Error("jBox2d_b2Body_ShouldCollideConnected(ground.m_jointList == null) error")
  }
  print(`jBox2d_b2Body_ShouldCollideConnected(ground.m_jointList == null): ${endTime - startTime} ms`)
}

function b2Body_SynchronizeFixtures_Test_01() {
  let gravity = new box2d.b2Vec2(0, -10)
  let world = new box2d.b2World(gravity);

  let def = new box2d.b2BodyDef()
  def.angle = 1
  def.position = new box2d.b2Vec2(1, 2)
  let body = world.CreateBody(def)
  body.m_activeFlag = true

  // fixture桥接body和shape之间的关系
  let shape = new box2d.b2PolygonShape()
  shape.Set([new box2d.b2Vec2(-4, -2)])
  body.CreateFixture(shape, 5.0);

  const startTime = getDate();
  for (let i = 0; i < runCount; i++) {
    body.SynchronizeFixtures();
  }
  const endTime = getDate();
  let a = JSON.stringify(box2d.b2Body.SynchronizeFixtures_s_xf1)
  if (
    JSON.stringify(box2d.b2Body.SynchronizeFixtures_s_xf1) !=
    '{"p":{"data":{"0":1,"1":2}},"q":{"s":0.8414709848078965,"c":0.5403023058681398}}'
  ) {
    throw new Error("jBox2d_b2Body_SynchronizeFixtures(body.m_activeFlag = true,body.m_fixtureList != null) error");
  }
  print(`jBox2d_b2Body_SynchronizeFixtures(body.m_activeFlag = true,body.m_fixtureList != null): ${endTime - startTime} ms`);
}

function b2Body_ResetMassData_Test_01() {
  let world = new box2d.b2World(new box2d.b2Vec2(0, -10))
  let def = new box2d.b2BodyDef()
  def.type = box2d.b2BodyType.b2_dynamicBody
  let body = world.CreateBody(def)

  let shape = new box2d.b2PolygonShape()
  shape.Set([new box2d.b2Vec2(-4, -2)])
  body.CreateFixture(shape, 5.0)
  body.m_mass = 3

  let data = new box2d.b2MassData()
  data.mass = 5
  data.I = 10
  data.center.Copy(new box2d.b2Vec2(1, 1))

  body.SetMassData(data)

  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    body.ResetMassData()
  }
  const endTime = getDate()
  if (
    body.m_mass != 20 ||
    body.m_invMass != 0.05 ||
    body.m_I != 13.333333333333332 ||
    body.m_invI != 0.07500000000000001 ||
    JSON.stringify(body.m_sweep.localCenter) != '{"data":{"0":0,"1":0}}'
  ) {
    throw new Error("jBox2d_b2Body_ResetMassData(body.m_fixtureList != null) error")
  }
  print(`jBox2d_b2Body_ResetMassData(body.m_fixtureList != null): ${endTime - startTime} ms`)
}

function b2PolygonShape_Set_Test_01() {
  let shape = new box2d.b2PolygonShape()
  const startTime = getDate()
  for (let i = 0; i < runCount; i++) {
    shape.Set([
      new box2d.b2Vec2(-4, -2),
      new box2d.b2Vec2(4, -2)
    ])
  }
  const endTime = getDate()
  let a = JSON.stringify(shape.m_vertices)
  if (JSON.stringify(shape.m_vertices) != '[{"data":{"0":-1,"1":-1}},{"data":{"0":1,"1":-1}},{"data":{"0":1,"1":1}},{"data":{"0":-1,"1":1}}]') {
    throw new Error('jBox2d_b2PolygonShape_Set(shape.m_vertices < 3) error')
  }
  print(`jBox2d_b2PolygonShape_Set(shape.m_vertices < 3): ${ endTime - startTime } ms`)
}

function b2PolygonShape_SetAsBox_Test_01() {
  let shape = new box2d.b2PolygonShape()
  shape.Set([
    new box2d.b2Vec2(-4, -2),
    new box2d.b2Vec2(4, -2),
    new box2d.b2Vec2(4, 0),
    new box2d.b2Vec2(-4, 0),
  ], 4)

  const startTime = getDate()
  for (let i = 0; i < runCount_thousnad_10; i++) {
    shape.SetAsBox(2, 4, new box2d.b2Vec2(1, 4))
  }
  const endTime = getDate()
  if (JSON.stringify(shape.m_vertices) != '[{"data":{"0":-1,"1":0}},{"data":{"0":3,"1":0}},{"data":{"0":3,"1":8}},{"data":{"0":-1,"1":8}}]') {
    throw new Error('jBox2d_b2PolygonShape_SetAsBox(shape.setAsBox.center != null) error')
  }
  print(`jBox2d_b2PolygonShape_SetAsBox(shape.setAsBox.center != null): ${ endTime - startTime } ms`)
}

function b2AABBTest() { // 12个
  b2AABB_Copy_Test()
  b2AABB_IsValid_Test()
  b2AABB_GetCenter_Test()
  b2AABB_GetExtents_Test()
  b2AABB_GetPerimeter_Test()
  b2AABB_Combine1_Test()
  b2AABB_Combine2_Test()
  b2AABB_Combine_Test()
  b2AABB_Contains_Test()
  b2AABB_RayCast_Test()
  b2AABB_TestContain_Test()
  b2AABB_TestOverlap_Test()
}

function b2WorldTest() { // 40个
  b2World_Test()
  b2World_CreateBody_Test()
  b2World_DestroyBody_Test()
  b2World__Joint_Create_Test()
  b2World__Joint_Destroy_Test()
  b2World_CreateJoint_Test()
  b2World_DestroyJoint_Test()
  b2World_CreateParticleSystem_Test()
  b2World_DestroyParticleSystem_Test()
  b2World_Step_Test()
  b2World_ClearForces_Test()
  b2World_GetBodyList_Test()
  b2World_GetJointList_Test()
  b2World_GetParticleSystemList_Test()
  b2World_GetContactList_Test()
  b2World_SetAllowSleeping_Test()
  b2World_GetAllowSleeping_Test()
  b2World_SetWarmStarting_Test()
  b2World_GetWarmStarting_Test()
  b2World_SetContinuousPhysics_Test()
  b2World_GetContinuousPhysics_Test()
  b2World_SetSubStepping_Test()
  b2World_GetSubStepping_Test()
  b2World_GetProxyCount_Test()
  b2World_GetBodyCount_Test()
  b2World_GetJointCount_Test()
  b2World_GetContactCount_Test()
  b2World_GetTreeHeight_Test()
  b2World_GetTreeBalance_Test()
  b2World_GetTreeQuality_Test()
  b2World_SetGravity_Test()
  b2World_GetGravity_Test()
  b2World_IsLocked_Test()
  b2World_SetAutoClearForces_Test()
  b2World_GetAutoClearForces_Test()
  b2World_ShiftOrigin_Test()
  b2World_GetContactManager_Test()
  b2World_GetProfile_Test()
  b2World_AddController_Test()
  b2World_RemoveController_Test()
}

function b2BodyTest() { // 70个
  b2Body_Test()
  b2Body_CreateFixture_Test()
  b2Body_CreateFixtureDef_Test()
  b2Body_CreateFixtureShapeDensity_Test()
  b2Body_DestroyFixture_Test()
  b2Body_SetTransformVec_Test()
  b2Body_SetTransformXY_Test()
  b2Body_SetTransform_Test()
  b2Body_GetTransform_Test()
  b2Body_GetPosition_Test()
  b2Body_SetPosition_Test()
  b2Body_SetPositionXY_Test()
  b2Body_GetAngle_Test()
  b2Body_SetAngle_Test()
  b2Body_GetWorldCenter_Test()
  b2Body_GetLocalCenter_Test()
  b2Body_SetLinearVelocity_Test()
  b2Body_GetLinearVelocity_Test()
  b2Body_SetAngularVelocity_Test()
  b2Body_GetAngularVelocity_Test()
  b2Body_GetDefinition_Test()
  b2Body_ApplyForce_Test()
  b2Body_ApplyForceToCenter_Test()
  b2Body_ApplyTorque_Test()
  b2Body_ApplyLinearImpulse_Test()
  b2Body_ApplyLinearImpulseToCenter_Test()
  b2Body_ApplyAngularImpulse_Test()
  b2Body_GetMass_Test()
  b2Body_GetInertia_Test()
  b2Body_GetMassData_Test()
  b2Body_SetMassData_Test()
  b2Body_ResetMassData_Test()
  b2Body_GetWorldPoint_Test()
  b2Body_GetWorldVector_Test()
  b2Body_GetLocalPoint_Test()
  b2Body_GetLocalVector_Test()
  b2Body_GetLinearVelocityFromWorldPoint_Test()
  b2Body_GetLinearVelocityFromLocalPoint_Test()
  b2Body_GetLinearDamping_Test()
  b2Body_SetLinearDamping_Test()
  b2Body_GetAngularDamping_Test()
  b2Body_SetAngularDamping_Test()
  b2Body_GetGravityScale_Test()
  b2Body_SetGravityScale_Test()
  b2Body_SetType_Test()
  b2Body_GetType_Test()
  b2Body_SetBullet_Test()
  b2Body_IsBullet_Test()
  b2Body_SetSleepingAllowed_Test()
  b2Body_IsSleepingAllowed_Test()
  b2Body_SetAwake_Test()
  b2Body_IsAwake_Test()
  b2Body_SetActive_Test()
  b2Body_IsActive_Test()
  b2Body_SetFixedRotation_Test()
  b2Body_IsFixedRotation_Test()
  b2Body_GetFixtureList_Test()
  b2Body_GetJointList_Test()
  b2Body_GetContactList_Test()
  b2Body_GetNext_Test()
  b2Body_GetUserData_Test()
  b2Body_SetUserData_Test()
  b2Body_GetWorld_Test()
  b2Body_SynchronizeFixtures_Test()
  b2Body_SynchronizeTransform_Test()
  b2Body_ShouldCollide_Test()
  b2Body_ShouldCollideConnected_Test()
  b2Body_Advance_Test()
  b2Body_GetControllerList_Test()
  b2Body_GetControllerCount_Test()
}

function b2ShapeTest() { // 77个
  b2Shape_Test()
  b2CircleShape_Clone_Test()
  b2ChainShape_Clone_Test()
  b2EdgeShape_Clone_Test()
  b2PolygonShape_Clone_Test()
  b2CircleShape_Copy_Test()
  b2Shape_GetType_Test()
  b2CircleShape_GetChildCount_Test()
  b2ChainShape_GetChildCount_Test()
  b2EdgeShape_GetChildCount_Test()
  b2PolygonShape_GetChildCount_Test()
  b2CircleShape_TestPoint_Test()
  b2ChainShape_TestPoint_Test()
  b2EdgeShape_TestPoint_Test()
  b2PolygonShape_TestPoint_Test()
  b2CircleShape_ComputeDistance_Test()
  b2ChainShape_ComputeDistance_Test()
  b2EdgeShape_ComputeDistance_Test()
  b2PolygonShape_ComputeDistance_Test()
  b2CircleShape_RayCast_Test()
  b2CircleShape_ComputeAABB_Test()
  b2CircleShape_ComputeMass_Test()
  b2CircleShape_SetupDistanceProxy_Test()
  b2CircleShape_ComputeSubmergedArea_Test()
  b2PolygonShape_Set_Test()
  b2PolygonShape_SetAsBox_Test()
  b2PolygonShape_Validate_Test()
  b2ChainShape_Copy_Test()
  b2EdgeShape_Copy_Test()
  b2PolygonShape_Copy_Test()
  b2ChainShape_RayCast_Test()
  b2EdgeShape_RayCast_Test()
  b2PolygonShape_RayCast_Test()
  b2ChainShape_ComputeAABB_Test()
  b2EdgeShape_ComputeAABB_Test()
  b2PolygonShape_ComputeAABB_Test()
  b2ChainShape_ComputeMass_Test()
  b2EdgeShape_ComputeMass_Test()
  b2PolygonShape_ComputeMass_Test()
  b2ChainShape_SetupDistanceProxy_Test()
  b2EdgeShape_SetupDistanceProxy_Test()
  b2PolygonShape_SetupDistanceProxy_Test()
  b2ChainShape_ComputeSubmergedArea_Test()
  b2EdgeShape_ComputeSubmergedArea_Test()
  b2PolygonShape_ComputeSubmergedArea_Test()
  b2PolygonShape_ComputeCentroid_Test()
  b2EdgeShape_Set_Test()
  b2CircleShape_Set_Test()
  b2ChainShape_CreateLoop_Test_01()
  b2ChainShape_CreateLoop_Test_02()
  b2ChainShape_CreateChain_Test()
  b2ChainShape_SetPrevVertex_Test()
  b2ChainShape_SetNextVertex_Test()
  b2ChainShape_GetChildEdge_Test()
  b2World_CalculateReasonableParticleIterations_Test()
  b2Fixture_ComputeDistance_Test()
  b2Fixture_RayCast_Test()
  b2Fixture_GetMassData_Test()
  b2Fixture_GetAABB_Test()
  b2Fixture_TestPoint_Test()
  b2World_GetTreeBalance_Test_01()
  b2World_CreateParticleSystem_Test_01()
  b2World_DestroyParticleSystem_Test_01()
  b2World_ShiftOrigin_Test_01()
  b2World_SetAllowSleeping_Test_01()
  b2World_GetProfile_Test_01()
  b2World_DestroyBody_Test_01()
  b2Body_CreateFixture_Test_01()
  b2Body_DestroyFixture_Test_01()
  b2Body_SetTransform_Test_01()
  b2Body_SetTransformXY_Test_01()
  b2Body_ShouldCollide_Test_01()
  b2Body_ShouldCollideConnected_Test_01()
  b2Body_SynchronizeFixtures_Test_01()
  b2Body_ResetMassData_Test_01() 
  b2PolygonShape_Set_Test_01()
  b2PolygonShape_SetAsBox_Test_01()
}

function runAllTest() {
  b2AABBTest();
  b2WorldTest();
  b2BodyTest();
  b2ShapeTest();
}

runAllTest();

// function print(str) {
//   console.log(str);
// }

function getDate() {
  return Date.now();
}